去'OR'标记枚举中的所有值

本文关键字:OR 枚举 | 更新日期: 2023-09-27 18:02:53

给定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值来计算它。

去'OR'标记枚举中的所有值

如果有一个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的情况下,可以很容易地添加另一个成员。

按位使用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);
}

对于泛型方法,使用Linq的Enumerable。聚合扩展方法;

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

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

mytest allValues = (mytest)int.MaxValue;

这里假设设置不对应于任何enum的位是没有问题的,但这很可能是真的。

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

all = max*2-1

只有在所有值都从1到最大值的情况下才有效。

1、2、4…64…

考虑到潜在的类型强制转换问题,这并不像乍看上去那么容易:

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);
        }
    }

关于这种转换的更多信息可以在这里找到