去'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
值来计算它。
如果有一个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);
}
}
关于这种转换的更多信息可以在这里找到