“标记枚举”中所有值的“OR”的最佳方法是什么?

时间:2013-03-08 16:06:24

标签: c# enums

鉴于enum

[Flags]
public enum mytest
{
    a = 1,
    b = 2,
    c = 4
}

我想出了两种方法来表示单个变量中的所有值:

    var OR1 = (mytest)Enum.GetNames(typeof(mytest)).Sum(a => (int)Enum.Parse(typeof(mytest), a));
    var OR2 = (mytest)(typeof(mytest).GetEnumValues() as mytest[]).Sum(a => (int)a);

现在,虽然它们都有效,但还有更简洁的方法吗?可能是我失踪的.NET方法?

编辑:为了澄清,我需要将该函数设置为动态 - 我不想通过指定每个enum值来计算它。

6 个答案:

答案 0 :(得分:20)

如果拥有All成员是有意义的,只需直接提供:

[Flags]
public enum mytest
{
    a = 1,
    b = 2,
    c = 4,
    All = 7
}

尽管如此,写一些更惯用的方式可能是:

[Flags]
public enum MyTest
{
    A = 1,
    B = 1 << 0x01,
    C = 1 << 0x02,
    All = A | B | C
}

这显示了枚举值的逻辑进展,并且在All情况下,可以轻松添加其他成员。

答案 1 :(得分:14)

使用Enumerable.Aggregate()按位或一起使用它们。即使您具有表示多个设置位的枚举值,这也将起作用,而不是Sum()

var myTestValues = (MyTest[]) typeof(MyTest).GetEnumValues();
var sum = myTestValues.Aggregate((a, b) => a | b);
sum.Dump();

使这个泛型变得有点棘手,因为你不能将泛型类型约束为枚举,原始类型也不能彼此有任何子类型关系。我能想出的最好的假设基础类型是int,它在大多数情况下都应该足够好:

TEnum AllEnums<TEnum>() 
{
    var values = typeof(TEnum).GetEnumValues().Cast<int>();
    return (TEnum) (object) values.Aggregate((a,b) => a|b);
}

答案 2 :(得分:6)

对于通用方法,请使用Linq的Enumerable.Aggregate扩展方法;

var flags = Enum.GetValues(typeof(mytest))
                .Cast<int>()
                .Aggregate(0, (s, f) => s | f);

或者在包装方法中

TEnum GetAll<TEnum>() where TEnum : struct
{
    return (TEnum) (object)
            Enum.GetValues(typeof(TEnum))
                .Cast<int>()
                .Aggregate(0, (s, f) => s | f);
}

这个双重演员的全部功劳归于@millimoose

答案 3 :(得分:1)

确保将所有枚举位设置为仅设置所有位的最简单方法:

mytest allValues = (mytest)int.MaxValue;

这假设设置与任何枚举不对应的位没有问题,但这可能是真的。你可以将它与任何枚举值进行对比,它会出现真实,这很可能是最终目标。

答案 4 :(得分:1)

这样的东西
var all = Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().Last() * 2 - 1;

基本上

all = max*2-1

仅当所有值都从1到最大值时才有效。

... 1,2,4 ... 32,64

答案 5 :(得分:0)

鉴于潜在的类型演员问题,它并不像第一眼看上去那么容易:

static public TEnum GetAllFlags<TEnum>() where TEnum : struct, IComparable, IFormattable, IConvertible
    {
        unchecked
        {
            if (!typeof(TEnum).IsEnum)
                throw new InvalidOperationException("Can't get flags from non Enum");
            object val = null;
            switch (Type.GetTypeCode(Enum.GetUnderlyingType(typeof(TEnum))))
            {
                case TypeCode.Byte:
                case TypeCode.SByte:
                    val = Enum.GetValues(typeof(TEnum))
                                .Cast<Byte>()
                                .Aggregate(default(Byte), ( s, f) => (byte)(s | f));
                    break;
                case TypeCode.Int16:
                case TypeCode.UInt16:
                    val = Enum.GetValues(typeof(TEnum))
                                .Cast<UInt16>()
                                .Aggregate(default(UInt16), ( s, f) => (UInt16)(s | f));
                    break;
                case TypeCode.Int32:
                case TypeCode.UInt32:
                    val = Enum.GetValues(typeof(TEnum))
                                .Cast<UInt32>()
                                .Aggregate(default(UInt32), ( s, f) => (UInt32)(s | f));
                    break;
                case TypeCode.Int64:
                case TypeCode.UInt64:
                    val = Enum.GetValues(typeof(TEnum))
                                .Cast<UInt64>()
                                .Aggregate(default(UInt64), ( s, f) => (UInt64)(s | f));
                    break;
                default :
                    throw new InvalidOperationException("unhandled enum underlying type");

            }
            return (TEnum)Enum.ToObject(typeof(TEnum), val);
        }
    }

有关此类转换的更多信息,请访问here