我有一个Person类,并创建了一个派生自EqualityComparer的等级竞争者类<人>。然而,默认的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并且ó等于
答案 0 :(得分:3)
让我们重新阅读您添加的引用:
Default属性检查类型T是否实现
System.IEquatable
接口,如果是,返回EqualityComparer 使用该实现。
因此,Default
属性会查找IEqutable<T>
的实现,Person
未提供。
如果对象未实现IEquatable<T>
,则:
否则,它返回一个EqualityComparer,使用由T提供的Object.Equals和Object.GetHashCode的覆盖。
其中显示了为什么object.Equals
和object.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>
(T
,List<T>
等中使用Contains
,它将调用您的IndexOf
实现。)或者当T
是字典的键并且您没有将任何自定义IEqualityComparer
传递给字典时。