编译器选择调用 IEquatable 的错误重载.等于

本文关键字:错误 重载 等于 选择 调用 IEquatable 编译器 | 更新日期: 2023-09-27 18:32:56

在性能敏感的程序中,我试图显式调用IEquatable<T>.Equals()而不是Object.Equals(以避免在我的情况下装箱)。 尽管我尽了最大的努力,编译器总是选择Object.Equals() - 我不明白。 人为的示例类:

class Foo : IEquatable<Foo>
{
    public bool Equals(Foo f)
    {
        Console.WriteLine("IEquatable.Equals");
        return true;
    }
    public override bool Equals(object f)
    {
        Console.WriteLine("Object.Equals");
        return true;
    }
}

同样人为的代码来演示问题:

// This calls IEquatable<Foo>
Foo f = new Foo();
f.Equals(f);
// This calls Object.Equals
IEquatable<Foo> i = new Foo();
i.Equals(i);

此代码的输出为:

IEquatable.Equals
Object.Equals

我读了乔恩·斯基特(Jon Skeet)关于重载的文章,但仍然不明白这里的问题。 所以我的问题是,如何在上面的变量i上显式调用IEquatable<Foo>.Equals

编译器选择调用 IEquatable<T> 的错误重载.等于

选择第二个重载的原因与调用方的类型无关。相反,它与您传递给Equals的参数类型有关。因此,即使您调用f.Equals(i),也会选择object.Equals方法。原因很简单,编译器会寻找最合适的重载。由于IEquatable<Foo>不一定是Foo的,因为可能有另一种类型,比如说Bar实现IEquatable<Foo>,在这种情况下,选择Equals(Foo f)重载是不对的(或不可能的)。

由于编译器不检查IEquatable<Foo>的基础类型,因此如果要调用Equals(Foo)重载,则需要显式强制转换为Foo参数。