!(a == b) 和 a != b 有区别吗?

28

我刚刚看到一段使用if(!(a == b))而不是常见的if(a != b)的代码,这在C#中是否有区别?


1
你在寻找什么样的差异? - Bogdan Doicin
你的代码示例是你看到的实际代码吗?因为我不认识任何开发者会用一对额外的括号来替换!=,除非实际代码比这个更复杂。 - Robert Harvey
1
小心使用其他语言,这是非常广泛的。在JavaScript中,这只有有时相同。 - Erik Philips
使用ILSpy反编译每个指令的IL代码。你看到有什么不同吗? - user47589
2
唯一的区别是将要阅读代码的工程师的理智,如果 (!(a == b))。 - rAndom69
相当长时间以前,我对C++也有同样的问题 - 这里只是为了比较而链接:https://dev59.com/LlsV5IYBdhLWcg3wrAZJ(这很困难...) - Marco13
3个回答

39
在大多数情况下,它们是相同的 - 但它们不必如此。!= 和 == 可以分别进行重载,具有不同的逻辑。这里有一个例子:
using System;

class Test
{
    // All this code is awful. PURELY FOR DEMONSTRATION PURPOSES.
    public static bool operator==(Test lhs, Test rhs) => true;
    public static bool operator!=(Test lhs, Test rhs) => true;        
    public override bool Equals(object other) => true;
    public override int GetHashCode() => 0;

    static void Main()
    {
        Test a = null;
        Test b = null;
        Console.WriteLine(a != b);    // True
        Console.WriteLine(!(a == b)); // False
    }    
}

在绝大多数情况下,a != b!(a == b)的行为完全相同,而a != b几乎总是更清晰明了的选择。但值得注意的是它们可能会有所不同。

甚至可以变得更加病态 - a != b!(a == b)甚至可能具有不同的类型。例如:

using System;

class Test
{
    // All this code is awful. PURELY FOR DEMONSTRATION PURPOSES.
    public static Test operator==(Test lhs, Test rhs) => new Test();
    public static Test operator!=(Test lhs, Test rhs) => new Test();
    public static string operator!(Test lhs) => "Negated";
    public override string ToString() => "Not negated";

    public override bool Equals(object other) => true;
    public override int GetHashCode() => 0;

    static void Main()
    {
        Test a = null;
        Test b = null;
        Console.WriteLine(a != b);    // "Not negated"
        Console.WriteLine(!(a == b)); // "Negated"
    }    
}

这里a != b的类型是Test,但是!(a == b)的类型是string。是的,这很糟糕,你在现实生活中不太可能遇到它 - 但这是C#编译器需要了解的一种情况。


8
这个非常具有推测性。 - Robert Harvey
5
比我快54秒。 - Eric Lippert
1
但值得注意的是,这是一个例子,说明如何找出为什么某些东西工作不正常(例如,开发人员对于类/对象比较过载了一个而不是另一个)。 - Erik Philips
1
@RobertHarvey:它的用意是表明就语言而言,这两个表达式是不同的。它们在几乎所有情况下可能会表现出相同的方式,但它们并不是同一件事情。 - Jon Skeet
6
学习面向对象编程已经接近30年了,但我仍然会混淆“重载”和“覆盖”的概念。 :-) 感谢Jon! - Eric Lippert
显示剩余8条评论

15
当然有差别。如果 !==!= 被重载,那么第一个调用前两个操作符,第二个调用第三个操作符。它们被允许做非常不同的事情,尽管这样做是愚蠢的。
事实上,在互相调用时,通常会使用重载的==!=操作符;例如,你可以说bool operator !=(C x, C y) => !(x == y);在这种情况下,x != y将会无限递归,这与调用 !(x == y)是完全不同的!

6
这个Jon Skeet是谁?总是使事情变得复杂。也许需要和长者们谈谈他。 - NTDLS

9

从逻辑和概念上讲,它们没有区别,但是由于运算符可以被重载,所以在实现上可能会有差异。

这突显了编程中的一个普遍点,即任何方法、运算符、属性或其他内容都应该准确地做“标签上标明的事情”。理想情况下,不应该有任何意外、不一致或隐藏在实现中的意外行为。


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