我正在使用带有几个位标记枚举的代码库工作,这些枚举看起来像这样
public enum BitMask
{
None = 0,
OptionA = 1 << 0,
OptionB = 1 << 1,
OptionAandB = OptionA | OptionB,
All = ~0
}
我可以使用
遍历所有枚举值public IEnumerable<T> EnumValues<T>()
{
return Enum.GetValues(typeof(T)).Cast<T>();
}
我正在寻找一种仅迭代单个标志值的通用方法,在这种情况下,是OptionA
和OptionB
。 不是 None
,OptionAandB
,All
。我可以强制转换为long
并检测单个标志,因为它们是2的幂,因此在此处进行快速搜索可以发现这一点
public bool IsPowerOfTwo(long val)
{
return (val != 0) && ((val & (val-1)) == 0) ;
}
非能量版本可以正常工作
public IEnumerable<BitMask> SingleFlagBitMaskValues()
{
return Enum.GetValues(typeof(BitMask))
.Cast<BitMask>()
.Where(e => IsPowerOfTwo((long)e));
}
但是通用版本无法编译,因为它不喜欢强制转换为long
public IEnumerable<TEnum> SingleFlagEnumValues<TEnum>()
{
return Enum.GetValues(typeof(TEnum))
.Cast<TEnum>()
.Where(e => IsPowerOfTwo((long)e));
}
有什么办法解决吗?
答案 0 :(得分:3)
由于Convert.ToInt64的许多重载,您可以使用它:
public IEnumerable<TEnum> SingleFlagEnumValues<TEnum>()
{
return Enum.GetValues(typeof(TEnum))
.Cast<TEnum>()
.Where(e => IsPowerOfTwo(Convert.ToInt64(e)));
}
正如评论中所建议的,这里是为了优化:
static class SingleFlagCache<TEnum>
{
internal static TEnum[] values = Enum.GetValues(typeof(TEnum))
.Cast<TEnum>()
.Where(e => IsPowerOfTwo(Convert.ToInt64(e))).ToArray();
}
public static IEnumerable<TEnum> SingleFlagEnumValues<TEnum>()
=> SingleFlagCache<TEnum>.values;
答案 1 :(得分:0)
这里是可供比较的替代版本:
public static IEnumerable<TEnum> SingleFlagEnumValues<TEnum>() where TEnum: struct, Enum
{
var type = typeof(TEnum);
foreach (int value in Enum.GetValues(type))
{
if (IsPowerOfTwo(value))
yield return (TEnum)(object)value;
}
}
(我的时间表明,这比使用Convert.ToInt64(e)
快1.5倍,但是对于如此快速的操作,这可能无关紧要。无论如何它仍然可以投射。)