c# - 永远不会调用覆盖相等运算符

标签 c# operator-overloading cil

这个类的方法

public class NullTester
{
    public bool EqualsNull<T>(T o) where T : class
    {
        return o == null;
    }

    public bool IsNull<T>(T o) where T : class
    {
        return o is null;
    }

    public bool EqualsCall<T>(T o) where T : class
    {
        return object.Equals(o, null);
    }
}

compile into this IL code:

.method public hidebysig 
    instance bool EqualsNull<class T> (
        !!T o
    ) cil managed 
{
    .maxstack 8

    IL_0000: ldarg.1
    IL_0001: box !!T
    IL_0006: ldnull
    IL_0007: ceq                                                          // IMPORTANT
    IL_0009: ret
} // end of method C::EqualsNull

.method public hidebysig 
    instance bool IsNull<class T> (
        !!T o
    ) cil managed 
{
    .maxstack 8

    IL_0000: ldarg.1
    IL_0001: box !!T
    IL_0006: ldnull
    IL_0007: ceq                                                          // IMPORTANT
    IL_0009: ret
} // end of method C::IsNull

.method public hidebysig 
    instance bool EqualsCall<class T> (
        !!T o
    ) cil managed 
{
    .maxstack 8

    IL_0000: ldarg.1
    IL_0001: box !!T
    IL_0006: ldnull
    IL_0007: call bool [mscorlib]System.Object::Equals(object, object)   // IMPORTANT
    IL_000c: ret
} // end of method C::EqualsCall

到目前为止,还不错。 但是 ceqSystem.Object::Equals(object, object) 都没有采用可能重写的 op_EqualityObject。等于

这是为什么呢?为什么建议的三种方法都不调用 operator== 或重写的 Equals 方法? System.Object::Equals(object, object) 不应该自动调用任何重写的 Equals 方法吗?


编辑: 我用于测试目的的类如下所示:

public class MyClass
{
     public static bool operator ==(MyClass m1, MyClass m2) => throw new Exception();

     public static bool operator !=(MyClass m1, MyClass m2) => throw new Exception();

     public override bool Equals(object obj) => throw new Exception();
}

下面的三个方法都没有调用任何 MyClass 的覆盖成员:

NullTester tester = new NullTester();
MyClass myClass = new MyClass(); 

tester.IsNull(myClass);
tester.EqualsNull(myClass);
tester.EqualsCall(myClass);

最佳答案

泛型的要点是:它们不是"template"。所有 T 都需要运行完全相同的 IL。这意味着,由于在您的示例中没有对 T 的约束,因此 IL 中唯一已知的运算符是 object 存在的运算符,因此 = =表示引用相等,同(object)x == (object)y

然而,多态性确实起作用。因此,您对 object.Equals(object)override 应该可以正常工作。但是:如果您使用 object.Equals(x, y)(静态方法)- 它会较早检查nullbefore 它调用您的方法。它知道 null 和“not null”在语义上不相等。如果您不希望这样:请不要使用静态 object.Equals(x, y)

您正在使用的静态Equals 方法可以表示为:

public static bool Equals(object objA, object objB) => 
    ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB)));

所以:(相同的引用,或者都为 null),或者(都不是 null,并且 x.Equals(y))

此实现避免了 x.Equals(y) 的不寻常实现可能具有类似 Equals(a, b)//trueEquals( b, a)//错误

关于c# - 永远不会调用覆盖相等运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49528820/

相关文章:

c# - 在 RavenDB LINQ 查询中使用日期字段比较

c# - 控制台 ReadKey 超时

c++ - 什么时候调用 const operator[],什么时候调用 non-const operator[]?

.net - MSIL 虚拟地址

c# - 方法的最后一条指令可能的操作码是什么?

c# - 如何在 .NET 中以编程方式密码保护 pdf?

c# - 有没有办法构造一个正则表达式来排除高于或低于某个值的 ASCII 字符?

C++ 插入 << 运算符重载

c++ - 模板类重载运算符的模糊调用

c# - 尝试保存 Emitted 程序集时抛出 NotSupportedException