【问题标题】:Enum as Flag using, setting and shifting枚举作为标志的使用、设置和移位
【发布时间】:2010-10-09 13:18:58
【问题描述】:

我有两个标志:

[Flags]
enum Flags
{
  A = 1,
  B = 2
};

我是这样设置的:

Mode = Flags.A | Flags.B; // default value
for(int i = 0; i < args.Length; i++) {
switch(args[i])
{
  case "--a":
  {
    if ((Mode & Flags.A) == Flags.A && (Mode & Flags.B) == Flags.B) 
     // both, default assume
    {
      Mode = Flags.A; // only A
    }
    else
    {
      Mode |= Flags.A; // append A
    }
    break;
  }
  case "--b":
  {
    if ((Mode & Flags.A) == Flags.A && (Mode & Flags.B) == Mode.B)
    {
      Mode = Flags.B;
    }
    else
    {
      Mode |= Flags.B;
    }
    break;
  }
} }

然后像这样使用它们:

if((Mode & Flags.A) == Flags.A)
{
 //
}
if((Mode & Flags.B) == Flags.B)
{
 //
}

主要保留:两个标志都可以设置。或者只是一个,在这种情况下只执行一部分代码。

我的代码好吗?设置标志的最佳方法是什么?

更新: 是不是先不那么丑了,你怎么看?

Mode = 0; // default value now is empty
for(int i = 0; i < args.Length; i++) {
switch(args[i])
{
  case "--a":
  {
    Mode |= Flags.A;
    break;
  }
  case "--b":
  {
    Mode |= Flags.B;
    break;
  }
} }
if(Mode == 0)
{
  Mode = Flags.A | Flags.B; // if no parameters are given, setup both flags
}

【问题讨论】:

  • 您的代码在语法上是正确的,但如果不进一步了解您的问题,就很难说它是否“好”。您的问题有点含糊,而您的回答问题则更加模糊。你能多给一点吗?从表面上看,您的解决方案对于所提出的问题来说太复杂了。
  • 嗨。有默认值 A|B。如果参数--a 只给A 设置模式,如果--b 只给B,并且如果两者都给(默认情况下)A|B。最好的检查方法是当前值是默认值 (A|B),如果需要,可以将其更改为 A 或 B。

标签: c# .net enums flags


【解决方案1】:

您可以使用以下精彩的语句关闭“位”:

Mode &= ~Flags.A;

我建议在您的枚举中也包含一个“null”值:

[Flags]
enum Flags
{
  Null = 0;
  A = 1,
  B = 2;
}

它会让你的生活更简单! :-)

【讨论】:

  • 谢谢,我去看看 &=~ !但是不同意你关于拥有空标志的观点。 MSDN 建议不要! msdn.microsoft.com/en-us/library/ms229062.aspx "没有办法检查是否显式设置了零值标志,而不是没有设置标志。"
  • 它不用于设置任何单独的位。它用于清除并给出定义的默认值。通过键入 if ( (Mode & Flags.A) != Flags.Null一个!
  • 我同意标志样式枚举的值为零,但 Microsoft 建议使用名称 None,而不是 Null - 如@abatishchev 链接到的文档中所述。
【解决方案2】:

第二个版本要好得多——这正是我要做的。将Mode == null 更改为Mode == 0

Mode = 0; // default value now is empty
for(int i = 0; i < args.Length; i++) {
    switch(args[i])
    {
        case "--a":
            Mode |= Flags.A;
            break;

        case "--b":
            Mode |= Flags.B;
            break;
    }
}

if(Mode == 0)
{
    Mode = Flags.A | Flags.B; // if no parameters are given, setup both flags
}

【讨论】:

    【解决方案3】:

    以下是我设置标志的方式:

    Mode = 0;
    for(int i = 0; i < args.Length; i++) {
        switch(args[i]) {
        case "--a":
            Mode |= Flags.A;
            break;
        case "--b":
            Mode |= Flags.B;
            break;
        }
    }
    

    如果默认情况下这两个标志都应打开,我认为将命令行参数更改为--not-a--not-b 更有意义。这既反映了默认设置,又让你摆脱了(Mode &amp; Flags.A) == Flags.A &amp;&amp; (Mode &amp; Flags.B) == Flags.B,这是相当丑陋的,恕我直言。

    然后你可以像这样设置你的标志:

    Mode = Flags.A | Flags.B;
    for(int i = 0; i < args.Length; i++) {
        switch(args[i]) {
        case "--not-a":
            Mode &= ~Flags.A;
            break;
        case "--not-b":
            Mode &= ~Flags.B;
            break;
        }
    }
    

    最后,如果你有很多标志(而不是只有两个),那么像这样设置你的枚举可能会更容易:

    [Flags]
    enum Flags
    {
        A = 1,
        B = 1 << 1,
        C = 1 << 2,
        D = 1 << 3,
        E = 1 << 4,
        F = 1 << 5
    };
    

    【讨论】:

    • 主要是关于默认值是A | B. 所以仅仅使用 |= 是不够的。
    • 我同意那段代码的丑陋,请看标题,你怎么看?
    • 新代码好多了,但我仍然认为 --not-a 和 --not-b 更有意义。另一方面,Mode 永远不会为 null(您将其设置为 0),因此您应该检查 Mode == 0。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多