布尔表达式,为什么只有两个术语?

时间:2010-06-09 15:29:37

标签: c# language-features boolean-expression

鉴于编写

是有效的
a = b = c = 2;

这也很好,而不是

bool allTwo = a == 2 && b == 2 && c == 2;

代替写

bool allTwo = a == b == c == 2;

但我不能,因为a == b的计算结果为布尔值,然后无法与整数进行比较。

是否存在以这种方式实施的语言设计原因?

8 个答案:

答案 0 :(得分:8)

表达式a == b的类型是布尔值,所以你要么必须破坏一个表达式,表达式无论其上下文是什么意思,或者有n-ary ==运算符,以便{{1} }被解析为a == b == c而不是(== a b c)。这意味着您需要(== (== a b) c)将布尔值c与(a == b) == c的结果进行比较,这是正常的,但不是C#在传统中的简单C语法风格。

答案 1 :(得分:5)

嗯,表达式c == 2将返回true,因此b将与true进行比较,而不是2。

编辑:这很可能是以这种方式实现的,因为C风格的语言处理布尔表达式。他们必须为多个术语制作一个特殊的例外并以不同的方式实现它,而使用赋值运算符则更直接:最正确的表达式求值为逻辑上可应用于链中下一个表达式的值。似乎设计师采用了简单的方法。

答案 2 :(得分:3)

从我的角度来看,这是一个清晰的问题。如果决定权由我决定,我会考虑如何添加这样的语言功能可能会增加关于复杂表达式的评估方式的含糊不清。在某些情况下,== b == c是否与(a == b)== c不同?如果我真的想将c与a == b的布尔结果进行比较而不是将c与b进行比较,该怎么办?在大多数情况下,编译器可能会找出正确的比较,但如果c可以隐式转换为bool,尽管不太可能,那么可能无法分辨。

所以个人而言,我不确定这是值得的麻烦。虽然它在语法上可能看起来不太好,但您可以构建自己的实用程序函数来比较多个对象的相等性,如下所示:

    public static bool Equals(this object x, params object[] y)
    {
        for (int i = 0; i < y.Length; i++)
        {
            if (!object.Equals(x, y[i]))
                return false;
        }
        return true;
    }

然后你可以像这样使用它:

        if (a.Equals(b, c, d, e, f, g))
        {
            // ...
        }

答案 3 :(得分:2)

我找不到引用,但我认为是Eric Lippert(?)谁发挥得最好:没有实现功能是免费的。另请参阅http://blog.ryjones.org/2005/07/12/product-development/http://blog.ryjones.org/2005/07/12/product-development/

他们有很多要实现的功能,我无法想象像这样的非标准值,可疑值是一个高优先级。我并不是说它没有价值,但它可能导致混乱,可能不会经常使用,等等。我认为a1ex07也有一个好处。这必须是一个自定义的情况,因为它不能再被一般地处理(==总是返回布尔值等)

你现在可以用LINQ做同样的事情,但语法有点复杂,需要分配某种数组:

bool allTwo = new int[] { a, b, c }.All(i => i == 2);

你可以倒退并检查是否有!= 2:

bool allNotTwo = new int[] { a, b, c }.Any(i => i != 2);

在这两种情况下,一旦失效,它也会退出,所以你经常不会浏览整个列表。

修改:这是另一点:Does C# have too many language features?

  

新的东西非常有用   把它变成语言

答案 4 :(得分:1)

要做你想做的事,operator ==应该返回对象。在这种情况下,我们将遇到另一个问题 - 现在我们需要将任何对象隐式转换为boolean。这样的转换也会产生额外的问题。

答案 5 :(得分:1)

我认为你的问题在你的参考点有些恶化。

a = b = c = 2没有什么可以暗示a == b == c == 2应该像你想要的那样工作 - 实际上更多 - 恰恰相反。

赋值运算符仅为2个操作数定义,并返回要设置的值。它们中的一串只是将每个运算符的值传递给下一个运算符:

1: a = (b = (c = 2));
2: a = (b = (2));
3: a = (2);

因此,a == b == c == 2也是如此:

1: bool allTwo = (a == (b == (c == 2)));
2: bool allTwo = (a == (b == ([Boolean])));
3: bool allTwo = (a == ([Boolean]));
4: bool allTwo = ([Boolean]);

因此,技术原因很简单,C#不包含对一串操作符进行特殊处理的定义。

至于语言设计和实现,原因可能是防止歧义和额外的复杂性。虽然您现在可能希望将a == b == c == 2定义为 所有相等的 运算符,但在下一行中您可能需要将其作为当前实现的行为。如何区分行为?并且真的值得努力实施吗?

或者a == 2 && b == 2真的那么糟糕吗? ;)

答案 6 :(得分:1)

忽略返回值,它还与operator associativity

有关

赋值运算符是右关联的。也就是说,首先评估赋值运算符的右侧。这就是为什么你可以a = b = c = 2并为它们分配值2的原因。否则,你最终会得到a的旧值bb c的旧值。

大多数其他运算符都是左关联运算符,尤其是短路逻辑运算符(&&||)。也就是说a == ba && b首先评估a

你可以说==可能是正确关联的...除了在.NET中它不能,因为对于对象,a == b是(除非被覆盖)转换为{{1} }(或者是a.Equals(b) ......我永远不记得了。)

答案 7 :(得分:-1)

不能直接回答您的问题,但如何:

bool allTwo = a & b & c == 2;
编辑:正如皮特所说,那是行不通的。怎么回事?

bool allEqual(params int[] inputs)
{
    int lastval = inputs[0];
    for (int i = 1; i < inputs.length; i++)
    {
        if (lastval != inputs[i])
            return false;

        lastval = inputs[i];
    }

    return true;
}

声明一次,随时使用它,并使用逗号分隔的整数列表进行比较。 (它可能有一个更简单的功能,但无论如何。)

bool allTwo = a == b && b == c && c == 2; // prefer this format over a == 2 && b == 2 && c == 2, personally

bool allTwo = allEqual(a, b, c, 2);

关于你的问题本身并没有什么可说的,这在其他人的答案中还没有说过。