如果我理解正确:C# 等式运算符 ( == ) 和操作数的顺序

Posted

技术标签:

【中文标题】如果我理解正确:C# 等式运算符 ( == ) 和操作数的顺序【英文标题】:If I understand correctly: C# Equality operator ( == ) and order of operands 【发布时间】:2018-05-13 23:49:33 【问题描述】:

有人提出了类似的问题,但我不确定我是否正确理解了答案。我指的是相等运算符在一个或两个类中被覆盖的情况。请解释我是否正确。如果我写if(a == b) ... ,则使用“a”类的相等运算符,如果使用if(b == a) ... ,则使用“b”类中定义的相等运算符。如果我写if(null == a) ... ,则使用哪个类的相等运算符。

【问题讨论】:

如果之前有人问过,但您仍然不明白,请参考前面的问题。另外 - 您查看过文档吗? 我英语不太好,但我写的是“相似”而不是“相同”的问题。感谢您提醒我有关文档的信息。 鉴于等式运算符是可交流的,并且 all and always 正确地覆盖了该运算符,因此可以认为该问题已结束。 阅读 C# 语言规范第 7.5.3 节 - 重载解决方案 【参考方案1】:

等式运算符在一个或两个类中被覆盖的情况

我们可以这样做并测试...类似于以下内容?

class A

    public static bool operator == (A a, B b)
    
        Console.WriteLine("A");
        return false;
    

    public static bool operator != (A a, B b)
    
        Console.WriteLine("A");
        return false;
    

    public static bool operator == (B b, A a)
    
        Console.WriteLine("A");
        return false;
    

    public static bool operator != (B b, A a)
    
        Console.WriteLine("A");
        return false;
    

    public override bool Equals(object o)
    
        return false;
    

    public override int GetHashCode()
    
        return 0;
    


class B

    public static bool operator == (A a, B b)
    
        Console.WriteLine("B");
        return false;
    

    public static bool operator != (A a, B b)
    
        Console.WriteLine("B");
        return false;
    

    public static bool operator == (B b, A a)
    
        Console.WriteLine("B");
        return false;
    

    public static bool operator != (B b, A a)
    
        Console.WriteLine("B");
        return false;
    

    public override bool Equals(object o)
    
        return false;
    

    public override int GetHashCode()
    
        return 0;
    

然后你编写如下代码:

A a = new A();
B b = new B();
if (a == b)

    // ...

然后你得到:

CS0034 运算符“==”在“A”和“B”类型的操作数上不明确

这是否回答了您的问题?看一下代码,当您定义运算符== 时,您指定参数的类型,编译器使用它来选择要调用的运算符。在这种情况下,它会找到两个运算符,它们按该顺序具有操作数 AB,并导致模棱两可的调用(编译器不知道 - 无法决定 - 使用哪一个)。

如果我写if(a == b) ... ,则使用“a”类的相等运算符,如果使用if(b == a) ... ,则使用“b”类中定义的相等运算符

这取决于操作数的类型。如果你总是把当前类的类型的操作数放在第一位,那是真的。例如:

void Main()

    A a = new A();
    B b = new B();
    if (a == b)
    
        // ...
    


class A

    public static bool operator == (A a, B b)
    
        Console.WriteLine("A");
        return false;
    

    public static bool operator != (A a, B b)
    
        Console.WriteLine("A");
        return false;
    

    public override bool Equals(object o)
    
        return false;
    

    public override int GetHashCode()
    
        return 0;
    


class B
   
    public static bool operator == (B b, A a)
    
        Console.WriteLine("B");
        return false;
    

    public static bool operator != (B b, A a)
    
        Console.WriteLine("B");
        return false;
    

    public override bool Equals(object o)
    
        return false;
    

    public override int GetHashCode()
    
        return 0;
    

输出:A

但是,如果以相反的顺序定义操作数的运算符...

void Main()

    A a = new A();
    B b = new B();
    if (a == b)
    
        // ...
    


class A

    public static bool operator == (B b, A a)
    
        Console.WriteLine("A");
        return false;
    

    public static bool operator != (B b, A a)
    
        Console.WriteLine("A");
        return false;
    

    public override bool Equals(object o)
    
        return false;
    

    public override int GetHashCode()
    
        return 0;
    


class B
   
    public static bool operator == (A a, B b)
    
        Console.WriteLine("B");
        return false;
    

    public static bool operator != (A a, B b)
    
        Console.WriteLine("B");
        return false;
    

    public override bool Equals(object o)
    
        return false;
    

    public override int GetHashCode()
    
        return 0;
    

输出:B

如果我写if(null == a) ... ,使用哪个类的相等运算符

首先,让我们明确一点。 B 或任何其他类在这里都无关紧要。它们不会影响此比较的结果,因为您没有在这里使用它们。如果他们这样做会很不方便。

让我们试试吧:

void Main()

    A a = new A();
    if (null == a)
    
        // ...
    


class A

    public static bool operator == (A a, B b)
    
        Console.WriteLine("A");
        return false;
    

    public static bool operator != (A a, B b)
    
        Console.WriteLine("A");
        return false;
    

    public override bool Equals(object o)
    
        return false;
    

    public override int GetHashCode()
    
        return 0;
    


class B
   
    public static bool operator == (B b, A a)
    
        Console.WriteLine("B");
        return false;
    

    public static bool operator != (B b, A a)
    
        Console.WriteLine("B");
        return false;
    

    public override bool Equals(object o)
    
        return false;
    

    public override int GetHashCode()
    
        return 0;
    

输出:.

我们没有得到任何输出,因为被调用的运算符不是此处定义的运算符...而是使用默认运算符(object 的运算符)。

等等!如果我改变操作数的顺序怎么办?

void Main()

    A a = new A();
    if (null == a)
    
        // ...
    


    class A

    public static bool operator == (B b, A a)
    
        Console.WriteLine("A");
        return false;
    

    public static bool operator != (B b, A a)
    
        Console.WriteLine("A");
        return false;
    

    public override bool Equals(object o)
    
        return false;
    

    public override int GetHashCode()
    
        return 0;
    


class B
   
    public static bool operator == (A a, B b)
    
        Console.WriteLine("B");
        return false;
    

    public static bool operator != (A a, B b)
    
        Console.WriteLine("B");
        return false;
    

    public override bool Equals(object o)
    
        return false;
    

    public override int GetHashCode()
    
        return 0;
    

输出:A

现在我们在 A 上使用运算符,因为它比默认运算符更好地匹配操作数类型。

【讨论】:

非常感谢您的全面回答。现在对我来说更清楚了。【参考方案2】:

Simply try it out.

public class Program

    public static void Main()
    
        var foo = new Foo();

        if(foo == null)
        
        

        if(null == foo)
        
        
    


public class Foo

    public static bool operator ==(Foo a, Foo b)
    
        Console.WriteLine("Foo operator == called");
        return ReferenceEquals(a, b);
    

    public static bool operator !=(Foo a, Foo b)
    
        Console.WriteLine("Foo operator != called");
        return !(a == b);
    

    public override bool Equals(object obj)
    
        Console.WriteLine("Foo Equals() called");
        return ReferenceEquals(this, obj);
    

    public override int GetHashCode()
    
        Console.WriteLine("Foo GetHashCode() called");
        return base.GetHashCode();
    

输出:

Foo operator == called
Foo operator == called

所以在这两种情况下,Foo 类的相等运算符都会被调用。

【讨论】:

非常感谢您的详细解答。你回答了我问题的第二部分。我可以通过与您的示例类比找到第一个的答案。

以上是关于如果我理解正确:C# 等式运算符 ( == ) 和操作数的顺序的主要内容,如果未能解决你的问题,请参考以下文章

多边形的布尔运算

相同“if”条件下的两个“==”等式运算符未按预期工作

简单的布尔不等式运算符错误

namedtuple 的等式重载

使用JS从等式中提取运算符和数字

IOS自动布局中位置属性约束方程的非恒等式