Update: See the bottom of this question for a C# workaround.
你好,
请考虑以下扩展方法:
public static bool HasFlags<T>(this T value,T flags) where T : System.Enum { // ... }
您可能会知道,这将在编译时抛出错误,因为类通常不允许继承自System.Enum.问题是使用枚举关键字指定的任何枚举实际上都是继承自System.Enum,因此上述代码将是将扩展方法限制为枚举的理想方式.
现在这里明显的工作是使用枚举而不是T,但是你失去了通用类型的好处:
MyEnum e; e.HasFlags(MyOtherEnum.DoFunkyStuff);
上面的代码将使用泛型类型抛出编译时错误,而它只能使用枚举类型(如果我实现它)来引发运行时错误.)
有没有任何编译器选项可以用来关闭约束检查,还是有其他一些漂亮的方法呢?
在建议之前,我想说,我不会使用T:struct或其他一些,因为你可以做一些奇怪的东西,如123.HasFlags(456).
我很遗憾为什么这个错误存在于所有…这是同样的问题,你会得到使用在哪里T:System.Object,但是,你有哪里T:类…为什么没有在哪里T:枚举?
C# workaround
Jon Skeet has started work on a library that compiles classes with a constraint to an
IEnumConstraint
,which is then replaced withSystem.Enum
post-build. This is,I believe,the closest one can get to working around this issue at this time.See:
- Code project: 07001
- Blog entry: 07002
If this workaround is unfeasible,you will have to write your library as C++/CLI code,which does not limit what can be used for generic type constraints (see the code in my answer below.)
解决方法
C#团队的成员之前曾表示过希望能够支持T:Enum和T:T代表的地位,但这并不是一个很高的优先级. (我不知道有什么理由是有限制在第一位,诚然…)
C#中最实用的解决方法是:
public static bool HasFlags<T>(this T value,T flags) where T : struct { if (!(value is Enum)) { throw new ArgumentException(); } // ... }
这会丢失对“枚举”的编译时检查,但是在两个地方都要保持检查是否使用相同的类型.当然,它还有执行时间的罚款.在第一次调用之后,您可以通过使用通用嵌套类型在静态构造函数中抛出异常的实现来避免执行时间的惩罚:
public static bool HasFlags<T>(this T value,T flags) where T : struct { if (!(value is Enum)) { throw new ArgumentException(); } return EnumHelper<T>.HasFlags(value,flags); } private class EnumHelper<T> where T : struct { static EnumHelper() { if (!typeof(Enum).IsAssignableFrom(typeof(T)) { throw new InvalidOperationException(); // Or something similar } } internal static HasFlags(T value,T flags) { ... } }
正如Greco所说,您可以在C/C++LI中编写该方法,然后从C#引用类库作为另一个选项.