4

鉴于它是有效的写

a = b = c = 2;

这也很好,而不是

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

改为写

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

但我不能,因为 a == b 评估为一个布尔值,然后不能与整数进行比较。

以这种方式实现是否有语言设计的原因?

4

8 回答 8

8

表达式的类型a == b是布尔值,因此您要么必须打破一个规则,即无论其上下文如何,表达式都意味着相同的事物,或者具有 n 元 == 运算符,以便将a == b == c其解析为(== a b c)而不是(== (== a b) c). 这意味着您需要(a == b) == c将布尔值 c 与 的结果进行比较(a == b),这可以,但不是 C# 传统的简单 C 语法风格。

于 2010-06-09T15:40:45.313 回答
5

好吧,表达式c == 2将返回true,因此 thenb将被与true而不是 2 进行比较。

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

于 2010-06-09T15:33:45.870 回答
3

从我的角度来看,这是一个清晰的问题。如果由我决定,我会考虑添加这样的语言功能可能会增加关于如何评估复杂表达式的太多歧义。在某些情况下 a == 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))
        {
            // ...
        }
于 2010-06-09T17:30:04.287 回答
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);

在这两种情况下,一旦其中一个无效,它也会立即退出,因此您通常不会浏览整个列表。

编辑: 还有一点:C# 有太多的语言特性吗?

一些新的东西对于把它变成语言非常有用

于 2010-06-09T15:57:57.997 回答
1

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

于 2010-06-09T15:45:19.370 回答
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真的那么糟糕?;)

于 2010-06-09T17:17:20.623 回答
1

忽略返回值,它还与运算符关联性有关

赋值运算符是右结合的。也就是说,赋值运算符的右侧首先被评估。这就是为什么您可以这样做a = b = c = 2并将它们全部分配值 2。否则,您最终会a得到旧值bb旧值c

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

您可能会争辩说这==可能是右关联的......除了在.NET中它不能,因为对于对象,a == b(除非被覆盖)转换为a.Equals(b)(或者是a.ReferenceEquals(b)......我不记得了)。

于 2010-06-09T17:40:41.570 回答
-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);

关于您的问题本身,我没有太多话要说,其他人的答案中还没有说过。

于 2010-06-09T15:36:28.390 回答