通用类型检查
有没有一种方法可以强制/限制传递给基元的类型? (布尔,整数,字符串等)
现在,我知道我们可以通过where子句将泛型类型参数限制为类型或者接口实现。但是,这并不适合基元(AFAIK),因为它们之间没有共同点(除了对象之前有人说过!:P)。
因此,我目前的想法是咬紧牙关,做一个大的switch语句,并在失败时抛出ArgumentException。
编辑1:
只是澄清一下:
代码定义应类似于:
public class MyClass<GenericType> ....
和实例化:
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)。有趣的问题不是吗? :)
这里是:
where T : struct
取自MSDN。
我很好奇..这可以在.NET 3.x中使用扩展方法来完成吗?创建一个接口,并在扩展方法中实现该接口(这可能比使用胖开关更干净)。另外,如果我们随后需要扩展到任何轻量级自定义类型,则它们也可以实现相同的接口,而无需对基本代码进行任何更改。
你们有什么感想?
不幸的消息是我正在Framework 2中工作!! :D
编辑3
这是Jon Limjaps Pointer撰写的非常简单的文章。非常简单,我几乎想哭了,但这很棒,因为代码就像一个魅力!
所以这就是我所做的(你会笑的!):
将代码添加到泛型类
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; } }
然后是一个小的实用程序方法来检查类型并引发异常,
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)!
解决方案
回答
public class Class1<GenericType> where GenericType : struct { }
这似乎很有效。
回答
使用自定义的FxCop规则,该规则标记" MyClass <>"的不受欢迎的用法。
回答
基元似乎是在TypeCode枚举中指定的:
也许有一种方法可以找出对象是否包含" TypeCode枚举",而不必将其强制转换为特定对象或者调用" GetType()"或者" typeof()"?
更新它就在我的鼻子底下。那里的代码示例显示了这一点:
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已经说了差不多的话:
//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),则可以始终执行以下操作:
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 <AnyTypeItDoesntMatter> .FromInt32`,这很烦人。如果要保持构造函数的私密性,则没有很好的解决方法,但是这里有一些解决方法:
- 创建一个抽象类MyClass。使MyClass <T>从MyClass继承,并将其嵌套在MyClass中。将静态方法移至" MyClass"。这将解决所有可见性问题,但必须以MyClass.MyClass <T>的身份访问MyClass <T>。
- 使用给定的
MyClass <T>
。创建一个静态类MyClass,使用MyClass <AnyTypeItDoesntMatter>调用MyClass <T>中的静态方法(可能每次都使用适当的类型,只是为了咯咯笑)。 - (更简单,但肯定很奇怪)创建一个抽象类型MyClass,它继承自MyClass <AnyTypeItDoesntMatter>。 (为具体起见,假设为" MyClass <int>"。)因为我们可以通过派生类的名称调用基类中定义的静态方法,所以现在可以使用" MyClass.FromString"。
这使我们可以进行静态检查,但要花更多的篇幅。
如果我们对动态检查感到满意,则可以在上面的TypeCode解决方案上使用一些变体。
回答
我们可以使用typeof(PrimitiveDataType).IsPrimitive属性来简化EnforcePrimitiveType方法。我想念什么吗?
回答
@Rob,因为Enum的TypeCode是Integer,它会通过TypeValid函数。我已经更新了该函数,以同时检查Enum
。
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