EqualityComparer<;T>;.默认不';t返回派生的EqualityComparer

本文关键字:EqualityComparer 返回 派生 默认 lt gt | 更新日期: 2023-09-27 18:24:40

我有一个类Person,并创建了一个从EqualityComparer<个人>。然而,默认的EqualityComparer不会调用我的Equals比较器的Equales函数

根据MSDN EqualityComparer<T>.默认属性:

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

在下面的(简化)示例中,类Person没有实现System.IEquatable<个人>。所以我希望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<个人>。

我的问题可与字符串的比较相媲美。有时,如果两个字符串完全相同,你希望它们相等,有时你希望忽略大小写,有时你想将字符视为óå等,就好像它们是字符o一样。

在我的例子中:我将Person存储在某个东西中,它可能是数据库,但也可能是File或MemoryStream。返回后,我得到一个标识符,在数据库的情况下,它当然是主键。有了这个键,我就可以检索到具有相同值的对象。

我想在单元测试中测试这一点:如果你在其中放了一些东西,你应该得到一个可以用来检索项目的密钥。遗憾的是,数据库并没有返回相同的Person,而是一个派生类Person(至少在使用EF6时是这样)。所以我不能使用普通的IEquatable,如果对象不是同一类型,它应该返回false。这就是为什么我想使用一个特殊的比较器,它声明两个Person相等,如果它们的属性值相同,即使它们都是来自Person的不同派生类。作为一个字符串比较器,它接受O和O,并且ó等于

EqualityComparer<;T>;.默认不';t返回派生的EqualityComparer

让我们重新阅读您添加的报价:

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>(如果可以实现这样的单个实现)。

您混淆了一些事情,但这并不奇怪,因为每个人都必须承认,.NET Framework有太多的平等比较可能性。

只有当您想为特定情况指定特殊的比较逻辑时,才应该实现IEqualityComparer<T>,例如对Dictionary<TKey, TValue>

EqualityComparer<T>在.NET中是一个令人困惑的可重写类型;但是,并不打算重写它,这样做也没有用。它为泛型类型提供了一个默认比较器,如果您在List<T>ContainsIndexOf等)中使用T,或者当T是字典的键并且没有向字典传递任何自定义IEqualityComparer时,它将调用您的IEquatable<T>实现。

这是因为EqualityComparer<T>Default属性不返回PersonComparer,而是返回ObjectEqualityComparer<T>。正如您参考文档所述,ObjectEqualityComparer<T>使用Person上的Equals进行比较。

请参阅实际来源。在第89行,它返回CCD_。

实际上,您的代码没有任何问题,正如您在PersonComparer:实例上实际运行代码时所看到的那样

bool b1 = new PersonComparer().Equals(x, y);
相关文章:
  • 没有找到相关文章