检查枚举是否有任何共同的标志

时间:2012-12-13 18:38:54

标签: c# enums flags enum-flags

考虑我有这种扩展方法:

public static bool HasAnyFlagInCommon(this System.Enum type, Enum value)
{
    var flags = value.ToString().Split(new string[] { ", " }, 
                                    StringSplitOptions.None);
    foreach (var flag in flags)
    {
        if (type.ToString() == flag)
            return true;
    }
    return false;
}

以下情况:

[Flags]
enum Bla
{
    A = 0,
    B = 1,
    C = 2,
    D = 4
}

Bla foo = Bla.A | Bla.B;
Bla bar = Bla.A;

bar.HasAnyFlagInCommon(foo); //returns true

我想检查foo是否有任何与bar相同的标志,但是在扩展方法中必须有更好的方法来实现这种行为。

我也尝试过这样,但总是返回true:

    public static bool HasAnyFlagInCommon(this System.Enum type, Enum value)
    {
        var flags = Enum.GetValues(value.GetType()).Cast<Enum>()
                                 .Where(item => value.HasFlag(item));
        foreach (var flag in flags)
        {
            if (type == flag)
                return true;
        }
        return false;
    }

3 个答案:

答案 0 :(得分:6)

您可以简单地将Enum值转换为 ulong (以考虑基础类型不是 int 的默认值的可能性)。如果结果!= 0,则至少设置了一个标志。

ulong theValue = (ulong)value;
return (theValue != 0);

请记住,在一天结束时,枚举由byte,sbyte,short,ushort,int,uint,long或ulong中的一个支持。

http://msdn.microsoft.com/en-us/library/sbbt4032.aspx

正在设置的标志与在后备类型中打开的相应位相同。如果所有位都关闭,上面的 ulong 将只为0。

答案 1 :(得分:2)

这样的东西
public static bool HasAnyFlagInCommon(this System.Enum type, Enum value)
{
    return (((long)type) & ((long)value)) != 0;
}

对于在两个枚举中设置的任何位,&都会给1,所以如果有任何这样的位,则结果为非零。

(我已经使用了long,希望它适用于enum的任何类型; int在你的情况下应该没问题。)

答案 2 :(得分:1)

我们有一个扩展方法,该扩展方法基于以下网站中描述的 Has()扩展方法:http://somewebguy.wordpress.com/2010/02/23/enumeration-extensions-2。它应该比转换成字符串更快,但是我还没有检查性能。相关子集为:

    /// <summary>
    /// Checks if an enumerated type contains a value
    /// </summary>
    public static bool Has<T>(this Enum value, T check) {
        Type type = value.GetType();

        //determine the values
        object result = value;
        _Value parsed = new _Value(check, type);
        if (parsed.Signed is long) {
            return (Convert.ToInt64(value)& (long)parsed.Signed) == (long)parsed.Signed;
        }
        else if (parsed.Unsigned is ulong) {
            return (Convert.ToUInt64(value) & (ulong)parsed.Unsigned) == (ulong)parsed.Unsigned;
        }
        else {
            return false;
        }
    }

    //class to simplfy narrowing values between 
    //a ulong and long since either value should
    //cover any lesser value
    private class _Value {

        //cached comparisons for tye to use
        private static Type _UInt64 = typeof(ulong);
        private static Type _UInt32 = typeof(long);

        public long? Signed;
        public ulong? Unsigned;

        public _Value(object value, Type type) {

            //make sure it is even an enum to work with
            if (!type.IsEnum) {
                throw new ArgumentException("Value provided is not an enumerated type!");
            }

            //then check for the enumerated value
            Type compare = Enum.GetUnderlyingType(type);

            //if this is an unsigned long then the only
            //value that can hold it would be a ulong
            if (compare.Equals(_Value._UInt32) || compare.Equals(_Value._UInt64)) {
                this.Unsigned = Convert.ToUInt64(value);
            }
            //otherwise, a long should cover anything else
            else {
                this.Signed = Convert.ToInt64(value);
            }

        }
    }