是否有针对“特殊类”的泛型类型约束的解决方法? C# 3.0 中的枚举?
更新:请参阅此问题的底部以获取 C# 解决方法。
您好,
请考虑以下扩展方法:
public static bool HasFlags<T>(this T value, T flags)
where T : System.Enum
{
// ...
}
正如您所知,这将在编译时抛出错误,因为通常不允许类继承自 System.Enum。问题是使用 enum
关键字指定的任何枚举实际上都是从 System.Enum
继承的,因此上面的代码是将扩展方法限制为枚举的理想方法仅有的。
现在,这里明显的解决方法是使用 Enum
而不是 T
,但是这样你就失去了泛型类型的好处:
MyEnum e;
e.HasFlags(MyOtherEnum.DoFunkyStuff);
上面的代码将抛出一个编译时错误泛型类型,而它只能使用 Enum
类型抛出运行时错误(如果我实现它的话)。
是否有任何编译器选项可用于关闭约束检查,或者是还有其他一些巧妙的方法可以做到这一点吗?
在建议之前,我想说我不会使用 where T : struct
或类似的东西,从那时起你就可以做一些奇怪的事情,比如 123.HasFlags( 456)
。
我很困惑为什么会存在这个错误...这与使用 where T : System.Object
遇到的问题相同,但为此你有 where T : class
...为什么没有where T : enum
?
C# 解决方法
Jon Skeet 已开始开发一个库,该库编译带有
IEnumConstraint
约束的类,然后在构建后用System.Enum
替换。我相信,这是目前最接近解决此问题的方法。参见:
- 代码项目:http://code.google.com/p/unconstrained-melody/
- 博客条目:http://msmvps.com/blogs/jon_skeet/archive/2009/09/10/generic-constraints-for-enums-and-delegates.aspx
如果此解决方法不可行,您将必须将库编写为 C++/CLI 代码,这不会限制可用于泛型类型约束的内容(请参阅下面我的答案中的代码。)
Update: See the bottom of this question for a C# workaround.
Hi there,
Consider the following extension method:
public static bool HasFlags<T>(this T value, T flags)
where T : System.Enum
{
// ...
}
This will, as you may know, throw an error at compile-time, since a class is not normally allowed to inherit from System.Enum
. The problem is that any enumeration specified using the enum
keyword does in fact inherit from System.Enum
, so the above code would be the ideal way to limit an extension method to enumerations only.
Now the obvious work-around here is to use Enum
instead of T
, but then you lose the benefits of generic types:
MyEnum e;
e.HasFlags(MyOtherEnum.DoFunkyStuff);
The above code would throw a compile-time error using generic types, while it can only throw a runtime error using the Enum
type (if I implement it to do so.)
Are there any compiler options that can be used to turn off the constraint check, or is there some other nifty way to do this?
Before it is suggested, I would like to say that I will not be using where T : struct
or some such, since then you'd be able to do weird stuff like 123.HasFlags(456)
.
I'm stumped as to why this error exists at all... It's the same problem you'd get using where T : System.Object
, but for that you have where T : class
... Why is there no where T : enum
?
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: http://code.google.com/p/unconstrained-melody/
- Blog entry: http://msmvps.com/blogs/jon_skeet/archive/2009/09/10/generic-constraints-for-enums-and-delegates.aspx
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.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
编辑:现在可以通过 ildasm/ilasm 支持此功能的库:UnconstrainedMelody。
C# 团队的成员之前曾表示他们希望能够支持
where T : Enum
和where T : Delegate
,但是那它从来都不是一个足够高的优先事项。 (诚然,我不确定首先进行限制的原因是什么......)C# 中最实用的解决方法是:
失去对“枚举性”的编译时检查,但保留检查您在两个地方都使用相同的类型。当然,它也有检查的执行时间损失。您可以通过使用泛型嵌套类型来实现在静态构造函数中抛出异常,从而避免第一次调用后的执行时间损失:
正如 Greco 提到的,您可以在 C++/CLI 中编写该方法,然后引用该类库C# 作为另一种选择。
EDIT: A library is now available supporting this via ildasm/ilasm: UnconstrainedMelody.
Members of the C# team have previously said they'd like to be able to support
where T : Enum
andwhere T : Delegate
, but that it's never been a high enough priority. (I'm not sure what the reasoning is for having the restriction in the first place, admittedly...)The most practical workaround in C# is:
That loses compile-time checking for the "enum-ness" but keeps the check that you're using the same type in both places. It has the execution-time penalty of the check as well, of course. You can avoid that execution-time penalty after the first call by using a generic nested type for the implementation which throws the exception in a static constructor:
As Greco mentions, you could write the method in C++/CLI and then reference the class library from C# as another option.
事实上,这是可能的,只是用了一个丑陋的把戏。
但是,它不能用于扩展方法。
如果需要,您可以为
Enums
提供一个私有构造函数和一个公共嵌套抽象继承类,其中Temp
作为Enum
,以防止非枚举的继承版本。Actually, it is possible, with an ugly trick.
However, it cannot be used for extension methods.
If you want to, you can give
Enums<Temp>
a private constructor and a public nested abstract inherited class withTemp
asEnum
, to prevent inherited versions for non-enums.我无法抗拒尝试 C++ 解决方法,既然我让它工作了,我想我应该与你们其他人分享它!
这是 C++ 代码(我的 C++ 非常生疏,所以请指出任何错误,特别是如何定义参数):
以及用于测试的 C# 代码(控制台应用程序):
I couldn't resist having a go at the C++ work-around, and since I got it to work I figured I'd share it with the rest of ya!
Here's the C++ code (my C++ is very rusty so please point out any errors, in particular how the arguments are defined):
And the C# code for testing (console application):
您可以使用 IL Weaving 和 ExtraConstraints 来实现此目的
允许您编写此代码
编译什么
You can achieve this using IL Weaving and ExtraConstraints
Allows you to write this code
What gets compiled