枚举作为标志的问题
Problems with Enum as Flags
我有以下 enum
:
[Flags]
public enum Status { Nominal, Modified, DirOneOnly, DirTwoOnly, DirOneNewest, DirTwoNewest }
我正在尝试查看 Modified
位是否已设置为真并尝试了以下方法:
if(_stateFlags.HasFlag(Status.Modified))
{
//DoStuff
} //Found out why this doesn't work after reading docs.
和
if((_stateFlags & Status.Modified) == Status.Modified)
{
//DoStuff
}
在我的进一步研究中,我相信后者是可行的方法。但是,当我执行 _stateFlags = Status.DirTwoOnly
时,上面的语句似乎仍然评估为 true
这真的让我感到困惑。
我是不是做错了什么?
You need to define the enum constants as powers of two.
[Flags]
public enum Status
{
Nominal = 1,
Modified = 2,
DirOneOnly = 4,
DirTwoOnly = 8,
DirOneNewest = 16,
DirTwoNewest = 32
}
class Program
{
static void Main(string[] args)
{
Status s = new Status();
s |= Status.Modified;
if (s.HasFlag(Status.Modified))
{
Console.WriteLine("Modified!");
}
}
}
代码:
[Flags]
public enum Status { Nominal, Modified, DirOneOnly, DirTwoOnly, DirOneNewest, DirTwoNewest }
等于:
[Flags]
public enum Status
{
Nominal = 0, // in bits: ... 0000 0000
Modified = 1, // 0000 0001
DirOneOnly = 2, // 0000 0010
DirTwoOnly = 3, // 0000 0011 **common bit with Modified state **
DirOneNewest = 4,
DirTwoNewest = 5,
}
所以正如其他人所说,您需要使用 2 的幂来计算枚举值。
您的问题有多个答案,说明了错误所在。我建议完全采用不同的方法。
Flags 枚举非常具有 1990 年代的感觉;如果您认为它们看起来像是用于 COM 互操作,并且如果您认为 COM 枚举看起来像是为了与 1970 年代的 bit-twiddling 代码兼容,那么您是对的。
我不会在新代码中将此逻辑表示为枚举。我会花时间编写一个自定义结构来清楚地表达我的实际语义。
struct Status
{
public static readonly Status None = default(Status);
private Status(int bits) { this.bits = bits; }
private int bits;
private const int NominalBitMask = 0b0001;
private const int ModifiedBitMask = 0b0010;
... etc ...
public bool IsNominal => (this.bits & NominalBitMask) != 0;
public Status WithNominal(bool f) =>
new Status(f ? (this.bits | NominalBitMask) : (this.bits & ~NominalBitMask));
... etc ...
现在您可以像这样使用它:
Status status = Status.None.WithNominal(true).WithModified(myFile.IsModified);
...
if (status.IsModified) ...
这是否需要更多的前期工作?当然,前面的工作还需要大约二十分钟。但是你再也不会犯任何微不足道的错误了。您有一个可以独立于使用它的逻辑进行测试的结构。你的代码看起来像它的意思。您永远不必担心有人将整数转换为您的枚举类型并让它充满废话。您可以将自定义逻辑放入您的类型中;例如,假设有 three-valued 标志——真、假或空——这些在标志枚举中很难做到,但您可以在自定义类型中轻松添加逻辑。等等。
我有以下 enum
:
[Flags]
public enum Status { Nominal, Modified, DirOneOnly, DirTwoOnly, DirOneNewest, DirTwoNewest }
我正在尝试查看 Modified
位是否已设置为真并尝试了以下方法:
if(_stateFlags.HasFlag(Status.Modified))
{
//DoStuff
} //Found out why this doesn't work after reading docs.
和
if((_stateFlags & Status.Modified) == Status.Modified)
{
//DoStuff
}
在我的进一步研究中,我相信后者是可行的方法。但是,当我执行 _stateFlags = Status.DirTwoOnly
时,上面的语句似乎仍然评估为 true
这真的让我感到困惑。
我是不是做错了什么?
You need to define the enum constants as powers of two.
[Flags]
public enum Status
{
Nominal = 1,
Modified = 2,
DirOneOnly = 4,
DirTwoOnly = 8,
DirOneNewest = 16,
DirTwoNewest = 32
}
class Program
{
static void Main(string[] args)
{
Status s = new Status();
s |= Status.Modified;
if (s.HasFlag(Status.Modified))
{
Console.WriteLine("Modified!");
}
}
}
代码:
[Flags]
public enum Status { Nominal, Modified, DirOneOnly, DirTwoOnly, DirOneNewest, DirTwoNewest }
等于:
[Flags]
public enum Status
{
Nominal = 0, // in bits: ... 0000 0000
Modified = 1, // 0000 0001
DirOneOnly = 2, // 0000 0010
DirTwoOnly = 3, // 0000 0011 **common bit with Modified state **
DirOneNewest = 4,
DirTwoNewest = 5,
}
所以正如其他人所说,您需要使用 2 的幂来计算枚举值。
您的问题有多个答案,说明了错误所在。我建议完全采用不同的方法。
Flags 枚举非常具有 1990 年代的感觉;如果您认为它们看起来像是用于 COM 互操作,并且如果您认为 COM 枚举看起来像是为了与 1970 年代的 bit-twiddling 代码兼容,那么您是对的。
我不会在新代码中将此逻辑表示为枚举。我会花时间编写一个自定义结构来清楚地表达我的实际语义。
struct Status
{
public static readonly Status None = default(Status);
private Status(int bits) { this.bits = bits; }
private int bits;
private const int NominalBitMask = 0b0001;
private const int ModifiedBitMask = 0b0010;
... etc ...
public bool IsNominal => (this.bits & NominalBitMask) != 0;
public Status WithNominal(bool f) =>
new Status(f ? (this.bits | NominalBitMask) : (this.bits & ~NominalBitMask));
... etc ...
现在您可以像这样使用它:
Status status = Status.None.WithNominal(true).WithModified(myFile.IsModified);
...
if (status.IsModified) ...
这是否需要更多的前期工作?当然,前面的工作还需要大约二十分钟。但是你再也不会犯任何微不足道的错误了。您有一个可以独立于使用它的逻辑进行测试的结构。你的代码看起来像它的意思。您永远不必担心有人将整数转换为您的枚举类型并让它充满废话。您可以将自定义逻辑放入您的类型中;例如,假设有 three-valued 标志——真、假或空——这些在标志枚举中很难做到,但您可以在自定义类型中轻松添加逻辑。等等。