C# 为所有枚举添加扩展方法,而不仅仅是特定类型的枚举

C# 为所有枚举添加扩展方法,而不仅仅是特定类型的枚举,c#,generics,enums,constraints,extension-methods,C#,Generics,Enums,Constraints,Extension Methods,编辑:这篇文章不是重复的,其他解决方案不允许我使用位运算符 我想这样做: public static class EnumExt { public static enum AddFlag(this enum e, enum flag) => e |= flag; } 所以我可以这样使用它: Color color = Red; color.AddFlag(Color.Dark); 它只是更容易阅读。我希望这个单一方法适用于所有枚举值,而不是对我计划使用的每个枚举值进行重写。问题

编辑:这篇文章不是重复的,其他解决方案不允许我使用位运算符

我想这样做:

public static class EnumExt
{
    public static enum AddFlag(this enum e, enum flag) => e |= flag;
}
所以我可以这样使用它:

Color color = Red;
color.AddFlag(Color.Dark);
它只是更容易阅读。我希望这个单一方法适用于所有枚举值,而不是对我计划使用的每个枚举值进行重写。问题是,该代码不起作用,因为
enum
的类型与
int
的类型不同。我试着用泛型做一些事情:

public static class EnumExt
{
    public static T AddFlag<T>(this T e, T flag) 
        where T : Enum      // Can't constrain to Enum
    {
        return e = e | flag;
    }
}
我的猜测是,即使这些限制仅限于
Enum
值,其他类仍有可能从
IEnumConstraint
IConvertible
继承,因此按位运算符将不起作用,因为它仍然不能保证操作对
t
可用


看起来唯一真正的解决方案是在C#7.3中,它们允许您使用
System.Enum
作为约束。

能够解决这个问题。我必须从
T
转换到
object
,然后转换到
int
,对
int
值使用位运算符,然后将其反转以返回结果

@mjwills指出,C#7.3不会解决铸造问题。它将修复的只是约束,我将能够删除抛出异常

public static T AddFlag<T>(this ref T e, T flag)
    where T : struct, IConvertible
{
    if (!(typeof(T).IsEnum)) throw new ArgumentException("Value must be an enum");

    int added = (int)(object)e | (int)(object)flag;

    e = (T)(object)added;

    return e;
}
public static T AddFlag(此ref T e,T标志)
其中T:struct,IConvertible
{
如果(!(typeof(T).IsEnum))抛出新的ArgumentException(“值必须是枚举”);
int added=(int)(object)e |(int)(object)标志;
e=(T)(对象)已添加;
返回e;
}

您安装了哪个版本的VS 2017可能存在重复?这是最新的预览吗?可能的副本有帮助吗?
// Doesn't work because C# won't allow bitwise operators on generic types 
// Because the constraint is still vague enough for non-enum values to slip through
public static T AddFlag<T>(this T e, T flag)
    where T : struct, IConvertible

// Doesn't work because enums don't inherit from IEnumConstraint
// Same as above
public static T AddFlag<T>(this T e, T flag)
    where T : struct, IEnumConstraint
public static T AddFlag<T>(this ref T e, T flag)
    where T : struct, IConvertible
{
    if (!(typeof(T).IsEnum)) throw new ArgumentException("Value must be an enum");

    int added = (int)(object)e | (int)(object)flag;

    e = (T)(object)added;

    return e;
}