枚举作为标志的问题

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 标志——真、假或空——这些在标志枚举中很难做到,但您可以在自定义类型中轻松添加逻辑。等等。