C# 枚举标志比较

7

考虑到以下标志,

  [Flags]
    public enum Operations
    {
        add = 1,
        subtract = 2,
        multiply = 4,
        divide = 8,
        eval = 16,
    }

我该如何实现IF条件来执行每个操作?在我的尝试中,第一个条件对于add, eval是正确的。然而,第一个条件也对于subtract, eval是正确的,这是不正确的。

        public double Evaluate(double input)
    {
        if ((operation & (Operations.add & Operations.eval)) == (Operations.add & Operations.eval))
            currentResult += input;
        else if ((operation & (Operations.subtract & Operations.eval)) == (Operations.subtract & Operations.eval))
            currentResult -= input;
        else
            currentResult = input;

        operation = null;

        return currentResult;
    }

我看不出问题在哪里。


1
这只是我一个人认为展示操作中的 [Flags] 不正确吗?我很难想到一个现实世界的例子,我会在数学操作中使用 Flags... - Sunny
我同意 Sunny 的看法。那些标记本应该代表计算器中的状态。我不确定为什么当初要这样做。回过头来看,现在我不会再这样做了。 - destructo_gold
可能是如何在C#中比较标志?的重复问题。 - Christoph Brückmann
5个回答

26

将内部的&替换为|

if ((operation & (Operations.add | Operations.eval)) == (Operations.add | Operations.eval))

这等价于:

if( ((operation & Operations.add)==Operations.add) &&
    ((operation & Operations.eval)==Operations.eval))

你可能更喜欢阅读这种写法,你也可以考虑使用这样的扩展:

public static bool HasFlag(this Operations op, Operations checkflag)
{
    return (op & checkflag)==checkflag;
}

那么你可以这样做:

if(operation.HasFlag(Operations.add) && Operations.HasFlag(Operations.eval))

这样可能会更易读。最后,您甚至可以创建此扩展以获得更多乐趣:

public static bool HasAllFlags(this Operations op, params Operations[] checkflags)
{
    foreach(Operations checkflag in checkflags)
    {
        if((op & checkflag)!=checkflag)
            return false;
    }
    return true;
}

那么您的表达式可以转化为:

if(operation.HasAllFlags(Operations.add, Operations.eval))

除非您认为这段代码难以阅读,否则您不需要单独编写“HasAllFlags”函数,因为您可以像这样使用“HasFlag”函数:if(operation.HasFlag(Operations.add | Operations.eval)) - weston

12

哇,我无法相信所有错误的答案……

如果你正在使用标志位,了解按位运算非常重要。在你的情况下,对于第一个条件,你有以下内容:

1 in binary is  00001
16 in binary is 10000

  00001
& 10000
--------
  00000

假设我们将减法(Subtract)(2)作为operation进行操作

2 in binary is     00010
previous result is 00000

  00010
& 00000
--------
  00000

由于之前的结果是00000,所以任何和它进行AND运算的结果都将为零。因此,你的条件语句将始终评估为true,因为0 == 0

如果我们仅仅改成OR,那么就会得到以下结果:

1 in binary is  00001
16 in binary is 10000

  00001
| 10000
--------
  10001 (17)

现在,假设我们有Add (1)作为operation

1 in binary is     00001
previous result is 10001 (17)

  00001
& 10001
--------
  00001

因此,1 & 17 => 1,因此您的最终条件为(1 & (1 | 16)) == (1 | 16) => 1 & 17 == 17 => 1 == 17 => false (仍为false!)

所以你实际想要的是:

((operation | Operations.add | Operations.eval) & (Operations.add | Operations.eval)) == (Operations.add | Operations.eval)

这将变成((1 | 1 | 16 ) & ( 1 | 16 )) == ( 1 | 16 ) => ( 17 & 17 ) == 17 => 17 == 17 == true

显然,这段代码难以理解,因此你应该选择将其提取为一个方法(如建议所示)。但重要的是要理解为什么你的条件是不正确的。


4

1
你的操作失败是因为表达式不正确。 (Operations.add&Operations.eval)永远为零。第一个比较的左右两边始终为零。请尝试使用以下代码,我认为这可能是您想要的:
public double Evaluate(double input)
{
    if ((operation & (Operations.add | Operations.eval)) == (Operations.add | Operations.eval))
        currentResult += input;
    else if ((operation & (Operations.subtract | Operations.eval)) == (Operations.subtract | Operations.eval))
        currentResult -= input;
    else
        currentResult = input;

    operation = null;

    return currentResult;
}

1

试试这个:

   public double Evaluate(double input)
{
    if ((operation & (Operations.add | Operations.eval)) == (Operations.add | Operations.eval))
        currentResult += input;
    else if ((operation & (Operations.subtract | Operations.eval)) == (Operations.subtract | Operations.eval))
        currentResult -= input;
    else
        currentResult = input;

    operation = null;

    return currentResult;
}

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