使用Enum作为Flag,进行设置和移位操作。

3

我有两个标记:

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

你的代码在语法上是正确的,但如果不更深入地了解你的问题,很难说它是否“好”。你的问题有点模糊,而你对答案的评论使其更加模糊。你能再多提供一些信息吗?从表面上看,你的解决方案对于所提出的问题来说过于复杂。 - Simon
嗨。默认值为A|B。如果给定参数--a,则仅将模式设置为A;如果只有--b,则仅将模式设置为B;如果两者都给定,则将模式设置为(默认)A|B。如何检查当前值是否为默认值(A|B),并在必要时将其更改为A或B是最佳方法。 - abatishchev
3个回答

9

这是我设置标志的方法:

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 & Flags.A) == Flags.A && (Mode & 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。因此,仅仅使用 |= 进行附加是不够的。 - abatishchev
我同意那段代码很丑陋,看一下帖子的头部,你觉得呢? - abatishchev
新代码要好得多,但我仍然认为--not-a和--not-b更有意义。另一方面,Mode永远不会为空(您将其设置为0),因此应检查Mode == 0。 - Can Berk Güder

2
您可以使用以下精彩语句关闭“位”:
Mode &= ~Flags.A;

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

我建议您在枚举中添加一个“null”值:

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

它将使您的生活更简单! :-)

谢谢,我会看一下 &=~!但是我不同意你关于拥有 null-flag 的观点。MSDN 建议不要这样做!http://msdn.microsoft.com/en-us/library/ms229062.aspx “没有办法检查是否显式设置了零值标志,而不是未设置任何标志。” - abatishchev
它不是用于设置任何单个位。它是用于清除并提供定义的默认值。如果通过键入if ((Mode&Flags.A)!= Flags.Null来测试位是否设置,则更容易进行测试。有许多原因为什么使用.Null值会使您的生活更简单。相信我! - Dan Byström
我同意对于标志风格的枚举使用零值,但是微软建议使用名称“None”,而不是“Null” - 正如@abatishchev链接中提到的那样。 - RenniePet

1
第二个版本要好得多 - 这正是我会做的事情。不过,请将 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
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接