EqualityComparer <t> .Default不返回派生的EqualityComparer

时间:2015-11-26 12:58:01

标签: c# iequalitycomparer

我有一个Person类,并创建了一个派生自EqualityComparer的等级竞争者类&lt;人&gt;。然而,默认的EqualityComparer不会调用我的相等比较器的等于函数

根据MSDN EqualityComparer < T > .Default property

  

Default属性检查类型T是否实现System.IEquatable接口,如果是,则返回使用该实现的EqualityComparer。否则,它返回一个EqualityComparer,它使用由T提供的Object.Equals和Object.GetHashCode的覆盖。

在下面的(简化)示例中,类Person没有实现实现System.IEquatable&lt;人&gt;。所以我希望PersonComparer.Default会返回PersonComparer的实例。

然而,没有调用PersonComparer.Equals。没有调试输出,返回值为false。

public class Person
{
    public string Name { get; set; }
}

public class PersonComparer : EqualityComparer<Person>
{
    public override bool Equals(Person x, Person y)
    {
        Debug.WriteLine("PersonComparer.Equals called");
        return true;
    }

    public override int GetHashCode(Person obj)
    {
        Debug.WriteLine("PersonComparer.GetHasCode called");
        return obj.Name.GetHashCode();
    }
}

public static void Main()
{
    Person x = new Person() { Name = "x" };
    Person y = new Person() { Name = "x" };
    bool b1 = PersonComparer.Default.Equals(x, y);
}

问题:我做错了什么?

如果您可能想知道为什么我不想实现IEquatable&lt;人&gt;。

我的问题与字符串的比较相当。有时你想要两个字符串是相同的,如果它们是完全相同的字符串,有时你想忽略大小写,有时你想把字符视为óò等所有就像它们是字符o一样。

在我的情况下:我将Person存储在可能是数据库的东西中,但它也可能是File或MemoryStream。返回时,我得到一个标识符,如果数据库当然是主键。使用此键,我可以检索具有相同值的对象。

我想在一个单元中测试这个测试:我把一些东西放进去,你应该得到一个可以用来检索项目的密钥。唉,数据库不返回相同的Person,而是返回Person的派生类(至少在使用EF 6时)。所以我不能使用正常的IEquatable,如果对象不是同一类型,它应该返回false。这就是为什么我想使用一个特殊的比较器,如果它们具有相同的属性值,则声明两个Persons相等,即使它们都是Person的不同派生类。与字符串比较器非常相似,它接受O和o并且ó等于

3 个答案:

答案 0 :(得分:3)

让我们重新阅读您添加的引用:

  

Default属性检查类型T是否实现System.IEquatable接口,如果是,返回EqualityComparer   使用该实现。

因此,Default属性会查找IEqutable<T>实现,Person未提供。

如果对象未实现IEquatable<T>,则:

  

否则,它返回一个EqualityComparer,使用由T提供的Object.Equals和Object.GetHashCode的覆盖。

其中显示了为什么object.Equalsobject.GetHashCode被调用的确切原因。您有两种选择,使用new PersonComparer().Equals(),或在您的类型上实施IEquatable<Person>(如果可以实现这样的单一实施)。

答案 1 :(得分:2)

这是因为Default的{​​{1}}属性不会返回EqualityComparer<T>,而是PersonComparer。在您引用文档时,ObjectEqualityComparer<T>使用ObjectEqualityComparer<T>上的Equals进行比较。

the actual source。在第89行,它返回Person

您的代码实际上没有任何问题,因为您可以看到实际尝试在ObjectEqualityComparer<T>的实例上运行代码时:

PersonComparer

答案 2 :(得分:0)

你混合了一些东西。没问题,必须承认.NET框架有a little bit too much possibilities进行相等比较。

仅当您想要将特殊比较逻辑传递给IEqualityComparer<T>时,才应实现Dictionary<TKey, TValue>

EqualityComparer<T>在.NET中是一个令人困惑的可覆盖类型;但是,并不打算覆盖它。它是泛型类型的默认比较器,如果您在IEquatable<T>TList<T>等中使用Contains,它将调用您的IndexOf实现。)或者当T是字典的键并且您没有将任何自定义IEqualityComparer传递给字典时。