确定具有 FlagsAttribute 的枚举是否具有唯一的位值
Determine if an Enum with FlagsAttribute has unique bit values
考虑以下枚举:
[Flags]
public enum EnumWithUniqueBitFlags
{
None = 0,
One = 1,
Two = 2,
Four = 4,
Eight = 8,
}
[Flags]
public enum EnumWithoutUniqueFlags
{
None = 0,
One = 1,
Two = 2,
Four = 4,
Five = 5,
}
第一个的值使得任何组合都会产生唯一的位组合,而第二个则不会。我需要以编程方式确定这一点。到目前为止,我只是在检查每个值是否是 2 的幂,但是由于此代码将用于使用其他人开发的枚举,因此不实用。
var values = Enum.GetValues(typeof(TEnum)).OfType<TEnum>().ToList();
for (int i = 0; i < values.Count; i++)
{
if (((int) ((object) values [i])) != ((int) Math.Pow(2, i)))
{
throw (new Exception("Whatever."));
}
}
与上面的代码相反,如何以编程方式确定以下枚举满足位组合唯一性 objective(不假设值是 2 的幂等)?
[Flags]
public enum EnumWithoutUniqueFlags
{
Two = 2,
Four = 9,
Five = 64,
}
请忽略枚举派生自哪种整数类型以及值可能为负的事实。
为了唯一,枚举必须没有与其他枚举值相同的位。 bitwise AND operation 可用于此。
for (int i = 0; i < values.Count; ++i)
{
for (int j = 0; j < values.Count; ++j)
{
if (i != j && ((values[i] & values[j]) != 0))
throw new Exception(...);
}
}
您可以比较枚举值的按位或与枚举值的算术和:
var values = Enum.GetValues(typeof(EnumWithoutUniqueFlags))
.OfType<EnumWithoutUniqueFlags>().Select(val => (int)val).ToArray();
bool areBitsUnique = values.Aggregate(0, (acc, val) => acc | val) == values.Sum();
编辑
正如@usr 提到的,上面的代码仅适用于正值。
尽管 OP 要求忽略:
Please ignore which integral type the enum derives from as well as the fact that values could be negative.
很高兴介绍更优化的单循环方法:
private static bool AreEnumBitsUnique<T>()
{
int mask = 0;
foreach (int val in Enum.GetValues(typeof(T)))
{
if ((mask & val) != 0)
return false;
mask |= val;
}
return true;
}
要使其适用于其他基础类型(uint
、long
、ulong
),只需更改 mask
和val
个变量。
EDIT2
由于 Enum.GetValues
方法 returns 值按其无符号大小的升序排列,如果您需要检查零值的重复项,可以使用以下方法:
private static bool AreEnumBitsUnique<T>()
{
int mask = 0;
int index = 0;
foreach (int val in Enum.GetValues(typeof(T)))
{
if ((mask & val) != 0) // If `val` and `mask` have common bit(s)
return false;
if (val == 0 && index != 0) // If more than one zero value in the enum
return false;
mask |= val;
index += 1;
}
return true;
}
我会将枚举转换为 uint,按位不是 0x0,使用异或,如果下一个值小于前一个值,就会发生冲突
public static bool CheckEnumClashing<TEnum>()
{
uint prev = 0;
uint curr = 0;
prev = curr = ~curr;
foreach(var target in Enum.GetValues(typeof(TEnum)).Select(a=>(uint)a))
{
curr ^=target;
if( curr <= prev )
return false;
prev = curr;
}
return true;
}
考虑以下枚举:
[Flags]
public enum EnumWithUniqueBitFlags
{
None = 0,
One = 1,
Two = 2,
Four = 4,
Eight = 8,
}
[Flags]
public enum EnumWithoutUniqueFlags
{
None = 0,
One = 1,
Two = 2,
Four = 4,
Five = 5,
}
第一个的值使得任何组合都会产生唯一的位组合,而第二个则不会。我需要以编程方式确定这一点。到目前为止,我只是在检查每个值是否是 2 的幂,但是由于此代码将用于使用其他人开发的枚举,因此不实用。
var values = Enum.GetValues(typeof(TEnum)).OfType<TEnum>().ToList();
for (int i = 0; i < values.Count; i++)
{
if (((int) ((object) values [i])) != ((int) Math.Pow(2, i)))
{
throw (new Exception("Whatever."));
}
}
与上面的代码相反,如何以编程方式确定以下枚举满足位组合唯一性 objective(不假设值是 2 的幂等)?
[Flags]
public enum EnumWithoutUniqueFlags
{
Two = 2,
Four = 9,
Five = 64,
}
请忽略枚举派生自哪种整数类型以及值可能为负的事实。
为了唯一,枚举必须没有与其他枚举值相同的位。 bitwise AND operation 可用于此。
for (int i = 0; i < values.Count; ++i)
{
for (int j = 0; j < values.Count; ++j)
{
if (i != j && ((values[i] & values[j]) != 0))
throw new Exception(...);
}
}
您可以比较枚举值的按位或与枚举值的算术和:
var values = Enum.GetValues(typeof(EnumWithoutUniqueFlags))
.OfType<EnumWithoutUniqueFlags>().Select(val => (int)val).ToArray();
bool areBitsUnique = values.Aggregate(0, (acc, val) => acc | val) == values.Sum();
编辑
正如@usr 提到的,上面的代码仅适用于正值。
尽管 OP 要求忽略:
Please ignore which integral type the enum derives from as well as the fact that values could be negative.
很高兴介绍更优化的单循环方法:
private static bool AreEnumBitsUnique<T>()
{
int mask = 0;
foreach (int val in Enum.GetValues(typeof(T)))
{
if ((mask & val) != 0)
return false;
mask |= val;
}
return true;
}
要使其适用于其他基础类型(uint
、long
、ulong
),只需更改 mask
和val
个变量。
EDIT2
由于 Enum.GetValues
方法 returns 值按其无符号大小的升序排列,如果您需要检查零值的重复项,可以使用以下方法:
private static bool AreEnumBitsUnique<T>()
{
int mask = 0;
int index = 0;
foreach (int val in Enum.GetValues(typeof(T)))
{
if ((mask & val) != 0) // If `val` and `mask` have common bit(s)
return false;
if (val == 0 && index != 0) // If more than one zero value in the enum
return false;
mask |= val;
index += 1;
}
return true;
}
我会将枚举转换为 uint,按位不是 0x0,使用异或,如果下一个值小于前一个值,就会发生冲突
public static bool CheckEnumClashing<TEnum>()
{
uint prev = 0;
uint curr = 0;
prev = curr = ~curr;
foreach(var target in Enum.GetValues(typeof(TEnum)).Select(a=>(uint)a))
{
curr ^=target;
if( curr <= prev )
return false;
prev = curr;
}
return true;
}