检查标志是否包含其他标志的任何值

Check if flag contains any value of other flag

我想比较两个标志,看看它们是否有任何共同的价值。
我希望有一个扩展方法来“加速”编码(我将经常在各种枚举类型上使用它)。我该怎么办?
这段代码告诉我:

operator '&' cannot be applied to operands of type enum and enum

public enum Tag
{
    Value1 = 1,
    Value2 = 2,
    Value3 = 4,
    Value4 = 8,
    Value5 = 16
}

public static class FlagExt
{
    public static bool HasAny(this Enum me, Enum other)
    {
        return (me & other) != 0;
    }
}

public class Program
{
    public static void Main()
    {
        Tag flag1 = Tag.Value1 | Tag.Value2 | Tag.Value3;
        Tag flag2 = Tag.Value2 | Tag.Value3 | Tag.Value4;
        
        Console.WriteLine(flag1.HasAny(flag2)); // it should returns true. flag1.HasFlag(flag2) returns false.
    }
}

我也试过这个:

    return (((int)me) & ((int)other)) != 0;

但它引发了错误:

Cannot convert type 'System.Enum' to 'int'

根据这个答案 (How to convert from System.Enum to base integer?)

您需要用异常处理程序包装此代码,或者以其他方式确保两个枚举都包含一个整数。

public static class FlagExt
{
    public static bool HasAny(this Enum me, Enum other)
    {
        return (Convert.ToInt32(me) & Convert.ToInt32(other)) != 0;
    }
}

如果您想要一个非常通用的 HasAny 枚举扩展,您可以执行以下操作。我已经测试过这适用于枚举可以是的所有不同的底层类型。此外,如果您正在检查标志,您可能应该使用 [Flags] 属性装饰您的枚举,因此这将检查被检查的枚举是否具有该属性。

public static class FlagExtensions
{
    public static bool HasAny(this Enum enumLeft, Enum enumRight)
    {
        if (enumLeft.GetType() != enumRight.GetType())
            throw new ArgumentException("enum types should be the same");
        
        if (!enumLeft.GetType().IsDefined(typeof(FlagsAttribute), inherit: false))
            throw new ArgumentException("enum type should have the flags attribute");
        
        dynamic enumLeftValue = Convert.ChangeType(enumLeft, enumLeft.GetTypeCode());
        dynamic enumRightValue = Convert.ChangeType(enumRight, enumRight.GetTypeCode());
        return (enumLeftValue & enumRightValue) != 0;
    }
}

I tried this as well:

return (((int)me) & ((int)other)) != 0;

but it raises the error:

Cannot convert type 'System.Enum' to 'int'

枚举总是实现 IConvertible 并且 IConvertible 具有 'ToInt32'。所以你可以这样写:

public static class FlagExt
{
    public static bool HasAny<TEnum>(this TEnum me, TEnum other) 
            where TEnum : Enum, IConvertible
    {
        return (me.ToInt32(null) & other.ToInt32(null)) != 0;
    }
}