是否有解决办法的泛型类型约束"特级"枚举在C#3.0吗? [英] Is there a workaround for generic type constraint of "special class" Enum in C# 3.0?

查看:178
本文介绍了是否有解决办法的泛型类型约束"特级"枚举在C#3.0吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  

更新:查看这个问题的底部为一个C#的解决方法

您好,

考虑下面的扩展方法:

 公共静态布尔HasFlags< T>(这件T值,T标志)
    其中T:System.Enum
{
    // ...
}
 

这个意愿,大家可能都知道,扔在编译时错误,因为一个类,一般是不允许从 System.Enum 继承。问题是,使用枚举关键字事实上确实从 System.Enum 继承指定的任何枚举,所以上述code将作为理想的方式来限制扩展方法来枚举只。

现在明显的工作在这里是使用枚举而不是 T ,但你失去的好处泛型类型的:

  MyEnumË;
e.HasFlags(MyOtherEnum.DoFunkyStuff);
 

以上code会使用泛型类型抛出一个编译时错误,但它只能通过抛出一个运行时错误的枚举类型(如果我实现它这样做。)

是否有可用于关闭约束检查的编译器选项,或者是有一些其他的漂亮的方式做到这一点?

在有人建议,我想说,我不会使用其中T:结构或一些这样的,因为那么你可以做怪异的东西,如 123.HasFlags(456)

我很为难,为什么这个错误存在于所有的...这是你开始使用,其中T同样的问题:System.Object的,但是对于你有其中T:类 ...为什么没有其中T:枚举

  

C#的解决方法

     

乔恩斯基特已经开始了编译类与约束的一个图书馆工作 IEnumConstraint ,然后将其与 System.Enum 生成后。这一点,我相信,最近的一个能够得到解决此问题的工作在这个时候。

     

请参阅:

     
      
  • code项目:<一href="http://$c$c.google.com/p/unconstrained-melody/">http://$c$c.google.com/p/unconstrained-melody/
  •   
  • 博客文章:<一个href="http://msmvps.com/blogs/jon%5Fskeet/archive/2009/09/10/generic-constraints-for-enums-and-delegates.aspx">http://msmvps.com/blogs/jon%5Fskeet/archive/2009/09/10/generic-constraints-for-enums-and-delegates.aspx
  •   
     

如果此解决办法是不可行的,你必须保证你的库为C ++ / CLI code,即不限制什么,可用于泛型类型的限制(见code。在我的回答如下。)

解决方案

编辑:库现在可以通过反汇编/ ILASM支持这一点:的 UnconstrainedMelody


C#团队的

成员有previously说他们的喜欢的是能够支持其中T:枚举其中T:代表,但它从来没有一个足够高的优先级。 (我不知道的理由是什么,有摆在首位的限制,无可否认...)

在C#中最实用的解决方法是:

 公共静态布尔HasFlags&LT; T&GT;(这件T值,T标志),其中T:结构
{
    如果(!(值枚举))
    {
        抛出新的ArgumentException();
    }
    // ...
}
 

这是失去编译时检查,为枚举性,但保持你正在使用相同类型的在这两个地方检查。它具有当然的检查的执行时间处罚为好,。您可以避免第一个电话后执行时间处罚用通用的嵌套类型而在静态构造函数抛出异常的实现:

 公共静态布尔HasFlags&LT; T&GT;(这件T值,T标志),其中T:结构
{
    如果(!(值枚举))
    {
        抛出新的ArgumentException();
    }
    返回EnumHelper&LT; T&GT; .HasFlags(值,标志);
}

私有类EnumHelper&LT; T&GT;其中T:结构
{
    静态EnumHelper()
    {
        如果(!typeof运算(枚举).IsAssignableFrom(typeof运算(T))
        {
            抛出新的InvalidOperationException异常(); //或类似的东西
        }
    }

    内部静态HasFlags(T价值,T标志)
    {
        ...
    }
}
 

由于希腊提到,你可以写在C ++ / CLI的方法,然后从C#引用类库作为另一种选择。

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 with System.Enum post-build. This is, I believe, the closest one can get to working around this issue at this time.

See:

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.)

解决方案

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 and where 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:

public static bool HasFlags<T>(this T value, T flags) where T : struct
{
    if (!(value is Enum))
    {
        throw new ArgumentException();
    }
    // ...
}

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:

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)
    {
        ...
    }
}

As Greco mentions, you could write the method in C++/CLI and then reference the class library from C# as another option.

这篇关于是否有解决办法的泛型类型约束&QUOT;特级&QUOT;枚举在C#3.0吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆