【发布时间】:2017-09-08 13:46:11
【问题描述】:
在比较自定义对象的两个集合时,我在使用 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() 方法时,重复的项目被 not 删除:
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吗?CompareTo方法还需要IComparable(T)。 -
我怀疑问题是您的
GetHashCode()逻辑存在缺陷。我认为您不需要执行任何特定的操作即可使其正常工作。可以发一下吗? -
“允许一些容忍度”听起来你也可能会破坏传递性。
-
@Jon 这用于比较两台不同计算机上的项目(该类被序列化和传输)。彼此相差几秒钟的项目应被视为相同,以允许存在细微的时钟差异。也许另一种方法会更好?
-
@JYelton:正如我所说,这打破了传递性,其中 x.equals(y) 和 y.equals(z) 意味着 x.equals(z)。 x 和 y 可能会延迟 3 秒,y 和 z 可能会延迟 3 秒......所以 x 和 z 可能会延迟 6 秒。如果你的容忍度是 5 秒,那么 bang 就具有传递性。