编译器选择错误的重载调用IEquatable <t> .Equals

时间:2016-02-03 09:15:46

标签: c# overloading iequatable

在性能敏感的程序中,我试图显式调用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的article on overloading并且离开时仍然没有理解这里的问题。所以我的问题是,如何在上面的变量IEquatable<Foo>.Equals上明确调用i

1 个答案:

答案 0 :(得分:5)

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

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