有没有一种方法可以强制/限制传递给基元的类型? (布尔,整数,字符串等)
现在,我知道您可以通过where子句将泛型类型参数限制为类型或接口实现。但是,这并不适合基元(AFAIK),因为它们并不具有共同点(除了对象之前有人说过!:P)。
因此,我目前的想法是咬紧牙关,做一个大的switch语句,并在失败时抛出ArgumentException。
编辑1:
只是澄清一下:
代码定义应类似于:
1
| public class MyClass<GenericType> .... |
和实例化:
1 2 3 4
| MyClass<bool> = new MyClass<bool>(); // Legal
MyClass<string> = new MyClass<string>(); // Legal
MyClass<DataSet> = new MyClass<DataSet>(); // Illegal
MyClass<RobsFunkyHat> = new MyClass<RobsFunkyHat>(); // Illegal (but looks awesome!) |
编辑2
@Jon Limjap-好点了,我已经考虑过了。.我确定有一个通用方法可以用来确定类型是值类型还是引用类型。
这在立即删除许多我不想处理的对象时可能很有用(但随后您需要担心所使用的结构,例如Size)。有趣的问题不是吗? :)
这里是:
取自MSDN。
我很好奇..这可以在.NET 3.x中使用扩展方法来完成吗?创建一个接口,并在扩展方法中实现该接口(这可能比使用胖开关更干净)。另外,如果您随后需要扩展到任何轻量级定制类型,则它们也可以实现相同的接口,而无需更改基本代码。
你们有什么感想?
不幸的消息是我正在Framework 2中工作!! :D
编辑3
这是Jon Limjaps Pointer撰写的非常简单的文章。非常简单,我几乎想哭了,但这很棒,因为代码就像一个魅力!
所以这就是我所做的(你会笑!):
将代码添加到泛型类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| bool TypeValid()
{
// Get the TypeCode from the Primitive Type
TypeCode code = Type.GetTypeCode(typeof(PrimitiveDataType));
// All of the TypeCode Enumeration refer Primitive Types
// with the exception of Object and Empty (Null).
// Since I am willing to allow Null Types (at this time)
// all we need to check for is Object!
switch (code)
{
case TypeCode.Object:
return false;
default:
return true;
}
} |
然后是一个小的实用程序方法来检查类型并引发异常,
1 2 3 4 5 6 7
| private void EnforcePrimitiveType()
{
if (!TypeValid())
throw new InvalidOperationException(
"Unable to Instantiate SimpleMetadata based on the Generic Type of '" + typeof(PrimitiveDataType).Name +
"' - this Class is Designed to Work with Primitive Data Types Only.");
} |
接下来要做的就是在类构造函数中调用EnforcePrimitiveType()。任务完成! :-)
唯一的缺点是,它只会在运行时(显然)而不是设计时抛出异常。.但这没什么大不了的,可以通过FxCop之类的实用程序(我们在工作中不使用)来解决。
特别感谢乔恩·林贾普(Jon Limjap)!
1 2 3
| public class Class1<GenericType> where GenericType : struct
{
} |
这似乎很有效。
似乎在TypeCode枚举中指定了基元:
也许有一种方法可以找出对象是否包含TypeCode enum而不必将其强制转换为特定对象或调用GetType()或typeof()?
更新它就在我的鼻子底下。那里的代码示例显示了这一点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| static void WriteObjectInfo(object testObject)
{
TypeCode typeCode = Type.GetTypeCode( testObject.GetType() );
switch( typeCode )
{
case TypeCode.Boolean:
Console.WriteLine("Boolean: {0}", testObject);
break;
case TypeCode.Double:
Console.WriteLine("Double: {0}", testObject);
break;
default:
Console.WriteLine("{0}: {1}", typeCode.ToString(), testObject);
break;
}
}
} |
这仍然是一个丑陋的开关。但这是一个很好的起点!
@Lars已经说了差不多的话:
1 2 3 4 5 6 7 8
| //Force T to be a value (primitive) type.
public class Class1< T > where T: struct
//Force T to be a reference type.
public class Class1< T > where T: class
//Force T to be a parameterless constructor.
public class Class1< T > where T: new() |
所有工作在.NET 2、3和3.5中。
如果您可以忍受使用工厂方法(而不是您要求的构造函数MyClass),则可以始终执行以下操作:
1 2 3 4 5 6 7 8 9 10
| class MyClass< T >
{
private readonly T _value;
private MyClass(T value) { _value = value; }
public static MyClass<int> FromInt32(int value) { return new MyClass<int>(value); }
public static MyClass<string> FromString(string value) { return new MyClass<string>(value); }
// etc for all the primitive types, or whatever other fixed set of types you are concerned about
} |
这里的问题是您将需要键入MyClass.FromInt32,这很烦人。如果要保持构造函数的私密性,则没有很好的解决方法,但是这里有一些解决方法:
-
创建一个抽象类MyClass。使MyClass< T >从MyClass继承并嵌套在MyClass中。将静态方法移到MyClass。这将解决所有可见性,但必须以MyClass.MyClass< T >身份访问MyClass< T >。
-
按给定使用MyClass< T >。制作一个静态类MyClass,该类使用MyClass调用MyClass< T >中的静态方法(可能每次都使用适当的类型,仅用于咯咯笑)。
-
(更简单,但肯定很奇怪)创建一个从MyClass继承的抽象类型MyClass。 (为具体起见,我们假设MyClass。)因为您可以通过派生类的名称调用基类中定义的静态方法,所以现在可以使用MyClass.FromString。
这使您可以进行静态检查,但要花费更多时间。
如果您对动态检查感到满意,则可以在上面的TypeCode解决方案上使用一些变体。
@Rob,Enum将滑过TypeValid函数,因为其TypeCode是Integer。我已经更新了该功能,还可以检查Enum。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Private Function TypeValid() As Boolean
Dim g As Type = GetType(T)
Dim code As TypeCode = Type.GetTypeCode(g)
' All of the TypeCode Enumeration refer Primitive Types
' with the exception of Object and Empty (Nothing).
' Note: must also catch Enum as its type is Integer.
Select Case code
Case TypeCode.Object
Return False
Case Else
' Enum's TypeCode is Integer, so check BaseType
If g.BaseType Is GetType(System.Enum) Then
Return False
Else
Return True
End If
End Select
End Function |
在遇到类似挑战时,我想知道你们对IConvertible接口的感觉如何。它允许请求者的要求,并且您可以扩展自己的实现。
例:
1 2 3 4 5
| public class MyClass<TKey>
where TKey : IConvertible
{
// class intentionally abbreviated
} |
我正在考虑将其作为解决方案,尽管许多建议也是我选择的一部分。
但是,我担心的是-使用您的课程的潜在开发人员是否会产生误解?
干杯-谢谢。
您可以使用typeof(PrimitiveDataType).IsPrimitive属性简化EnforcePrimitiveType方法。我想念什么吗?
使用自定义的FxCop规则来标记MyClass<>的不良用法。