16

鉴于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值来计算它。

4

6 回答 6

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情况下,可以轻松添加另一个成员。

于 2013-03-08T16:08:58.413 回答
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);
}
于 2013-03-08T16:10:38.557 回答
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

于 2013-03-08T16:08:34.777 回答
1

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

mytest allValues = (mytest)int.MaxValue;

这假设设置不对应于任何枚举的位没有问题,但这很可能是真的。您可以将其与任何枚举值相结合,结果将成真,这很可能是最终目标。

于 2013-03-08T16:18:39.730 回答
1

像这样的东西怎么样

var all = Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().Last() * 2 - 1;

基本上

all = max*2-1

这仅适用于从 1 到最大值的所有值。

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

于 2013-03-08T16:25:57.810 回答
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);
        }
    }

可以在此处找到有关此类转换的更多信息

于 2013-12-21T00:00:37.407 回答