简体   繁体   English

用枚举作为标志的问题

[英]Problems with Enum as Flags

I have the following enum : 我有以下enum

[Flags]
public enum Status { Nominal, Modified, DirOneOnly, DirTwoOnly, DirOneNewest, DirTwoNewest }

I am attempting to see whether the Modified bit has been set to true and have tried the following methods: 我正在尝试查看Modified位是否已设置为true,并尝试了以下方法:

if(_stateFlags.HasFlag(Status.Modified))
{
    //DoStuff
}   //Found out why this doesn't work after reading docs.

and

if((_stateFlags & Status.Modified) == Status.Modified)
{
    //DoStuff
}

The latter is the method that my further research led me to believe would work. 后者是我的进一步研究使我相信可以使用的方法。 However, when I do _stateFlags = Status.DirTwoOnly the above statement still seems to evaluate to true which is really puzzling me. 但是,当我执行_stateFlags = Status.DirTwoOnly ,上面的语句似乎仍然为true ,这真让我感到困惑。

Am I doing something fundamentally wrong? 我是从根本上做错了吗?

You have several answers to your question explaining what is wrong. 您对问题有几个答案,可以解释出什么问题。 I would suggest taking a different approach entirely. 我建议完全采用其他方法。

Flags enums have a very 1990s feel to them; 标记枚举对他们有1990年代的感觉。 if you think they look like they're there for COM interop, and if you think COM enums look like they are for compatibility with bit-twiddling code from the 1970s, you're right. 如果您认为它们看起来像是用于COM互操作的,并且您认为COM枚举看起来是为了与1970年代的位纠缠代码兼容,那么您是对的。

I would not express this logic as an enum in new code. 我不会将此逻辑表示为新代码中的枚举。 I would take the time to write a custom struct that clearly expresses my actual semantics. 我会花时间编写一个清晰表达我实际语义的自定义结构。

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 ...

And now you can use it like: 现在您可以像这样使用它:

Status status = Status.None.WithNominal(true).WithModified(myFile.IsModified);
...
if (status.IsModified) ...

Is this more work up front? 还有更多工作吗? Sure, it's about twenty minutes more work up front. 当然,还有大约二十分钟的工作要做。 But you then never make any bit twiddling mistake ever again. 但是,您再也不会犯任何纠缠不清的错误了。 You have a struct you can test independently of the logic that uses it. 您拥有一个可以独立于使用它的逻辑进行测试的结构。 You have code that looks like what it means. 您的代码看起来像是什么意思。 You never have to worry about someone casting an integer to your enum type and having it full of nonsense. 您永远不必担心有人将整数转换为您的枚举类型并使其毫无意义。 You can put custom logic in your type; 您可以在类型中添加自定义逻辑; suppose for example there are three-valued flags -- true, false or null, say -- those are hard to do in flags enums but you can add the logic easily in a custom type. 例如,假设存在三值标志(例如,true,false或null),这在标志枚举中很难做到,但是您可以轻松地在自定义类型中添加逻辑。 And so on. 等等。

You need to define the enum constants as powers of two. 您需要将枚举常量定义为2的幂。

[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!");
        }
    }
}

The code: 编码:

[Flags]
public enum Status { Nominal, Modified, DirOneOnly, DirTwoOnly, DirOneNewest, DirTwoNewest }

is equal to: 等于:

[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,

} }

So as other people said, you need to use power of 2 for enum values. 因此,正如其他人所说,枚举值需要使用2的幂。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM