通用types检查

有没有办法强制/限制传递给基元的types? (bool,int,string等)

现在,我知道你可以通过where子句将genericstypes参数限制为types或接口实现。 然而,这不符合基本法(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 – 好点,和我已经考虑的东西..我敢肯定有一个通用的方法,可以用来确定types是一个值或引用types..

这可能会立即删除很多我不想处理的对象(但是你需要担心使用的结构,如大小 )有用的..有趣的问题没有? 🙂

这里是:

 where T : struct 

取自MSDN 。


我很好奇..可以使用扩展方法在.NET 3.x中完成? 创build一个接口,并在扩展方法中实现接口(这可能比一个胖开关更清洁)。 此外,如果您稍后需要扩展到任何轻量级自定义types,则它们也可以实现相同的接口,而不需要对基本代码进行更改。

你们有什么感想?

可悲的消息是我在Framework 2工作! :d


编辑3

从Jon Limjaps指针开始,这个过程非常简单。这么简单,我几乎要哭,但是它很棒,因为代码就像一个魅力!

所以这就是我所做的(你会笑!):

添加到generics类的代码

 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; } } 

然后用一些实用的方法来检查types并抛出一个exception,

 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() 。 任务完成! 🙂

唯一的缺点是,它只是在运行时抛出一个exception(显然),而不是devise时。但这没什么大不了的,可以用像FxCop这样的工具来获取。

特别感谢Jon Limjap对这一个!

看起来在TypeCode枚举中指定了基元:

也许有办法找出一个对象是否包含TypeCode enum而不必将其转换为特定的对象或调用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; } } } 

这仍然是一个丑陋的开关。 但是这是一个开始的好地方!

 public class Class1<GenericType> where GenericType : struct { } 

这个似乎做的工作..

几乎@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 } 

这里的一个问题是,你将需要inputMyClass<AnyTypeItDoesntMatter>.FromInt32 ,这是烦人的。 如果你想保持构造函数的私有性,这里没有一个很好的解决方法,但是这里有几个解决方法:

  • 创build一个抽象类MyClass 。 使MyClass<T>MyClassinheritance并将其嵌套在MyClass 。 将静态方法移到MyClass 。 这将使所有的可视性工作,代价是必须访问MyClass<T> MyClass.MyClass<T>
  • 按给定的方式使用MyClass<T> 。 创build一个静态类MyClass ,它使用MyClass<AnyTypeItDoesntMatter>调用MyClass<T>的静态方法(可能每次都使用相应的types,只是为了咯咯笑)。
  • (更容易,但肯定怪异的) MyClass<AnyTypeItDoesntMatter>inheritance的抽象typesMyClass<AnyTypeItDoesntMatter> 。 (具体来说,让我们说MyClass<int> 。)因为你可以通过派生类的名称调用基类中定义的静态方法,现在可以使用MyClass.FromString

这会让你静态检查,而牺牲更多的写作。

如果您对dynamic检查感到满意,我会在上面的TypeCode解决scheme上使用一些变体。

@Rob, Enum的将滑过TypeValid函数,因为它的TypeCodeInteger 。 我已经更新了函数来检查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 

您可以通过使用typeof(PrimitiveDataType).IsPrimitive属性来简化EnforcePrimitiveType方法。 我错过了什么吗?

使用自定义的FxCop规则来标记MyClass<>不良使用。

有一个类似的挑战,我想知道你们如何看待IConvertible接口 。 它允许请求者需要什么,并且可以使用自己的实现进行扩展。

例:

  public class MyClass<TKey> where TKey : IConvertible { // class intentionally abbreviated } 

我想这是一个解决scheme,尽pipe许多build议也是我select的一部分。

然而,我担心的是,潜在的开发者使用你的课程是否会产生误导?

干杯 – 谢谢。