自定义通用SetFlag / UnsetFlag扩展方法

时间:2015-01-27 10:11:14

标签: c# generics enums

在我幼稚的天真中,我决定为Enums构建通用的SetFlagUnsetFlag扩展方法,因此没有人必须在我的代码中读取和重读并重新读取按位运算符:

public static void SetFlag<T>(this T en, T flag)  where T : Enum {
    en |= flag;
}

public static void UnsetFlag<T>(this T en, T flag) where T : Enum
{
    en &= ~flag;
}

现在我收到运算符|=不适用于TT类型的错误,而运算符~则不适用于T类型。< / p>

我认为我必须将T更改为“Enum”类型“HasFlags”。这是问题的真正根源,我将如何改变它?

1 个答案:

答案 0 :(得分:3)

这是我的方法。正如我在问题的评论中所说,我强烈反对在生产代码中使用这些方法:

    public static T SetFlag<T>(this T en, T flag) where T : struct, IConvertible
    {
        int value = en.ToInt32(CultureInfo.InvariantCulture);
        int newFlag = flag.ToInt32(CultureInfo.InvariantCulture);

        return (T)(object)(value | newFlag);
    }

    public static T UnsetFlag<T>(this T en, T flag) where T : struct, IConvertible
    {
        int value = en.ToInt32(CultureInfo.InvariantCulture);
        int newFlag = flag.ToInt32(CultureInfo.InvariantCulture);

        return (T)(object)(value & ~newFlag);
    }

用法:

[Flags]
public enum Flags
{
    None = 0, A = 1, B = 2, C = 4
}

Flags flags = Flags.A.SetFlag(Flags.C);
flags = flags.UnsetFlag(Flags.C);

正如您所看到的,我使用了它,每个枚举都实现了IConvertible。所以我在这个接口上定义了扩展方法,它也提供了一个方便的方法,用于将枚举值转换为int。这样做的一个副作用是您可以将此方法用于实现此接口的每个其他类型。所以你可以滥用这种方法:

int a = 0;
a = a.SetFlag(5); // a == 5
a = a.UnsetFlag(4); // a == 1