use*_*754 4 c# enums bit-manipulation bitwise-operators
说我有以下枚举:
[Flags]
enum IntFlags
{
A = 1 << 0,
B = 1 << 1,
C = 1 << 2,
AAndB = A | B
}
Run Code Online (Sandbox Code Playgroud)
我想构建一个帮助方法,设置如下所示的标志:
private static IntFlags Set(IntFlags values, IntFlags target)
{
return target | values;
}
Run Code Online (Sandbox Code Playgroud)
有没有灵活的方法来进行一些健全性检查?就像不应该设置枚举中不存在的值或不是现有值的组合.
以下内容不应该是可能的:
IntFlags flags = 0;
flags = Set(0, flags);
flags = Set((IntFlags)int.MaxValue, flags);
flags = Set(~IntFlags.A, flags);
Run Code Online (Sandbox Code Playgroud)
我想只是对现有的值进行检查,例如:
private static IntFlags Set(IntFlags values, IntFlags target)
{
if (!Enum.GetValues(typeof(IntFlags)).Cast<IntFlags>().Contains(values))
throw new ArgumentException();
return target | values;
}
Run Code Online (Sandbox Code Playgroud)
将无法正常工作,因为设置值如
IntFlags flags = 0;
flags = Set(IntFlags.A | IntFlags.C, flags);
Run Code Online (Sandbox Code Playgroud)
应该被允许.
我认为这可能有效:
IntFlags Set(IntFlags values, IntFlags target)
{
int intValue;
if (int.TryParse(values.ToString(), out intValue))
{
throw new ArgumentException();
}
...
}
Run Code Online (Sandbox Code Playgroud)
但这取决于我在枚举上使用Flags属性的事实.
编辑
我现在找到了Enum.IsDefined()方法.它很好用
Assert.False(Enum.IsDefined(typeof(IntFlags), (IntFlags)int.MaxValue));
Assert.False(Enum.IsDefined(typeof(IntFlags), 0));
Assert.False(Enum.IsDefined(typeof(IntFlags), ~IntFlags.A));
Run Code Online (Sandbox Code Playgroud)
但是我的要求没有合并的价值
Assert.True(Enum.IsDefined(typeof(IntFlags), IntFlags.A | IntFlags.C)); //fails
Run Code Online (Sandbox Code Playgroud)
没有办法静态地禁止用户Enum创建表示底层类型的任何值的枚举.您只能在运行时进行此类验证,如问题中所示.
如果你只是在寻找一种简单的验证方法,那么在运行时,如果一个特定的枚举值是一个有效的标志组合,那么这是一个足够简单的检查,假设定义的枚举值实际上增加了2的幂.对于这样的枚举,所有有效值将从0到1小于下一个最大2的幂,因此检查将变为:
if((int)values > 0 && (int)values >= 1 << 3))
throw new ArgumentException();
Run Code Online (Sandbox Code Playgroud)
从技术上讲,您可以通过映射每个值来删除所有可能的未映射值,但这不是一个特别实用的解决方案.
如果其中任何一个都不是一个选项,你剩下的就是不使用an Enum,而是使用你自己的自定义类型,它具有你想要的确切语义:
public class IntFlags
{
public int Value { get; private set; }
private IntFlags(int value)
{
this.Value = value;
}
public static readonly IntFlags A = new IntFlags(1);
public static readonly IntFlags B = new IntFlags(2);
public static readonly IntFlags C = new IntFlags(4);
public static IntFlags operator |(IntFlags first, IntFlags second)
{
return new IntFlags(first.Value | second.Value);
}
public override bool Equals(object obj)
{
return Equals(obj as IntFlags);
}
public override bool Equals(IntFlags obj)
{
return obj != null && Value == obj.Value;
}
}
Run Code Online (Sandbox Code Playgroud)