c# - 在自定义对象集合上使用 LINQ 时,IEquatable<T>、IEqualityComparer<T> 和覆盖 .Equals() 之间的区别?

标签 c# linq

在比较自定义对象的两个集合时,我在使用 Linq 的 .Except() 方法时遇到了一些困难。

我从 Object 派生了我的类并为 Equals() 实现覆盖, GetHashCode()和运算符 ==!= .我还创建了一个 CompareTo()方法。

在我的两个集合中,作为调试实验,我从每个列表中取出第一项(重复)并将它们进行如下比较:

itemListA[0].Equals(itemListB[0]);     // true
itemListA[0] == itemListB[0];          // true
itemListA[0].CompareTo(itemListB[0]);  // 0

三种情况下,结果都如我所愿。然而,当我使用 Linq 的 Except() 方法时,重复项没有被删除:

List<myObject> newList = itemListA.Except(itemListB).ToList();

了解 Linq 如何进行比较,我发现了各种(相互冲突的?)方法,这些方法表明我需要从 IEquatable<T> 继承。或 IEqualityComparer<T>等等

我很困惑,因为当我继承自,例如,IEquatable<T> , 我需要提供一个新的 Equals()与我已经覆盖的签名不同的方法。我是否需要两个具有不同签名的方法,或者我是否应该不再从 Object 派生我的类? ?

我的对象定义(简化)如下所示:

public class MyObject : Object
{
    public string Name {get; set;}
    public DateTime LastUpdate {get; set;}

    public int CompareTo(MyObject other)
    {
        // ...
    }

    public override bool Equals(object obj)
    {
        // allows some tolerance on LastUpdate
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int hash = 17;
            hash = hash * 23 + Name.GetHashCode();
            hash = hash * 23 + LastUpdate.GetHashCode();
            return hash;
        }
    }

    // Overrides for operators
}

我注意到当我从 IEquatable<T> 继承时我可以使用 IEquatable<MyObject> 来做到这一点或 IEquatable<object> ; Equals() 的要求当我使用一个或另一个时签名更改。推荐的方式是什么?

我想要完成的事情:

我希望能够在不重复代码的情况下使用 Linq (Distinct/Except) 以及标准相等运算符(==!=)。如果两个对象的名称相同并且LastUpdate,比较应该允许两个对象被认为是相等的属性在几秒(用户指定)的公差范围内。

编辑:

正在显示 GetHashCode()代码。

最佳答案

是否覆盖object.Equals并不重要和 object.GetHashCode , 实现 IEquatable ,或提供 IEqualityComparer .所有这些都可以工作,只是方式略有不同。

1) 覆盖 EqualsGetHashCode来自 object :

从某种意义上说,这是基本情况。它通常会起作用,假设您能够编辑类型以确保这两种方法的实现符合需要。在许多情况下,这样做并没有错。

2) 实现 IEquatable

这里的关键点是你可以(并且应该)实现IEquatable<YourTypeHere> .这和 #1 之间的主要区别在于您对 Equals 进行了强类型化。方法,而不仅仅是让它使用 object .这既方便了程序员(增加了类型安全性),也意味着任何值类型都不会被装箱,因此这可以提高自定义结构的性能。如果你这样做,你应该总是 除了 #1 之外,而不是代替它。拥有 Equals这里的方法在功能上不同于 object.Equals会……不好。不要那样做。

3) 实现 IEqualityComparer

这与前两个完全不同。这里的想法是对象没有得到它自己的哈希码,或者看它是否等于其他东西。这种方法的要点是,一个对象不知道如何正确地获取它的散列值或查看它是否等于其他东西。也许是因为您不控制类型的代码(即第 3 方库)并且他们没有费心去覆盖行为,或者他们确实覆盖了它但您只想要自己对“平等”的独特定义这个特定的上下文。

在这种情况下,您创建了一个完全独立的“比较器”对象,它接受两个不同的对象并通知您它们是否相等,或者一个对象的哈希码是什么。使用此解决方案时,Equals 是什么并不重要或 GetHashCode方法在类型本身中执行,您不会使用它。


请注意,所有这些与 == 完全无关运算符,这是它自己的野兽。

关于c# - 在自定义对象集合上使用 LINQ 时,IEquatable<T>、IEqualityComparer<T> 和覆盖 .Equals() 之间的区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15797780/

相关文章:

c# - 网络核心 : Find Primary Key of Entity Framework Core and Reflection

c# - 用于可选分配的可空类型(不是集合)的 Protobuf-net 模式

c# - 如何将 LINQ 查询变成匿名类型

c# - 返回结果还是先放到变量中?

c# - 从 asp.net c# 设置 style.display

c# - 基于 Windows 8.1 构建的 .NET 4.0 程序集不适用于较低的 Windows 版本

c# - 有没有办法使用部分填充的对象搜索 List<T>?

C# 'Enumerable.Repeat()'如何重载?

c# - 将 MemberExpression 应用于对象以检索属性值

c# - 在 C# 中使用 Regex 提取 Form 标记中的操作属性?