linq&distinct,实现equals和gethashcode

所以我正在努力使这项工作,我似乎无法知道为什么它不起作用

演示代码;

namespace ConsoleApplication1 { class Program { static void Main(string[] args) { var myVar = new List(); myVar.Add(new parent() { id = "id1", blah1 = "blah1", c1 = new child() { blah2 = "blah2", blah3 = "blah3" } }); myVar.Add(new parent() { id = "id1", blah1 = "blah1", c1 = new child() { blah2 = "blah2", blah3 = "blah3" } }); var test = myVar.Distinct(); Console.ReadKey(); } } public class parent : IEquatable { public String id { get;set;} public String blah1 { get; set; } public child c1 { get; set; } public override int GetHashCode() { unchecked // Overflow is fine, just wrap { int hash = 17; // Suitable nullity checks etc, of course :) hash = hash * 23 + id.GetHashCode(); hash = hash * 23 + blah1.GetHashCode(); hash = hash * 23 + (c1 == null ? 0 : c1.GetHashCode()); return hash; } } public bool Equals(parent other) { return object.Equals(id, other.id) && object.Equals(blah1, other.blah1) && object.Equals(c1, other.c1); } } public class child : IEquatable { public String blah2 { get; set; } public String blah3 { get; set; } public override int GetHashCode() { unchecked // Overflow is fine, just wrap { int hash = 17; // Suitable nullity checks etc, of course :) hash = hash * 23 + blah2.GetHashCode(); hash = hash * 23 + blah3.GetHashCode(); return hash; } } public bool Equals(child other) { return object.Equals(blah2, other.blah2) && object.Equals(blah3, other.blah3); } } } 

任何人都可以发现我的错误?

您需要覆盖Equals(object)方法:

 public override bool Equals(object obj) { return Equals(obj as parent); } 

object.Equals方法(与EqualityComparer.Default )不使用IEquatable接口。 因此,当您编写object.Equals(c1, other.c1) ,它不会调用您的Child.Equals(Child)方法。

parent也不一定非常需要这样做,但你真的应该这样做。

您可以执行SLaks建议的操作,也可以在parent类中使用EqualityComparer.Default来使用IEquatable实现:

  public bool Equals(parent other) { return object.Equals(id, other.id) && object.Equals(blah1, other.blah1) && EqualityComparer.Default.Equals(c1, other.c1); } 

在添加计算哈希时,您可能想要尝试类似的东西

hash ^= id.GetHashCode();

不确定这是否是导致您的问题的原因。

这里有几件事要做。 如果我要在GetHashCodeIEquatable ==或IEquatable等类中实现相等的任何方面,我总是使用以下模式。

  1. 覆盖等于
  2. 覆盖GetHashCode
  3. 实现IEquatable ,这意味着实现Equals(T)
  4. 实施!=
  5. 实施==

所以,如果我有一个名为ExpiryMonth的类,其属性为Year和Month,那么这就是该实现的外观。 现在适应其他类型的课程是一项相当盲目的任务。

我已将此模式基于其他几个stackoverflow答案,这些答案都值得赞扬,但我一直没有跟踪。

通过始终将所有这些元素一起实现,它确保在各种上下文中进行适当的相等操作,包括字典和Linq操作。

  public static bool operator !=(ExpiryMonth em1, ExpiryMonth em2) { if (((object)em1) == null || ((object)em2) == null) { return !Object.Equals(em1, em2); } else { return !(em1.Equals(em2)); } } public static bool operator ==(ExpiryMonth em1, ExpiryMonth em2) { if (((object)em1) == null || ((object)em2) == null) { return Object.Equals(em1, em2); } else { return em1.Equals(em2); } } public bool Equals(ExpiryMonth other) { if (other == null) { return false; } return Year == other.Year && Month == other.Month; } public override bool Equals(object obj) { if (obj == null) { return false; } ExpiryMonth em = obj as ExpiryMonth; if (em == null) { return false; } else { return Equals(em); } } public override int GetHashCode() { unchecked // Overflow is not a problem { var result = 17; result = (result * 397) + Year.GetHashCode(); result = (result * 397) + Month.GetHashCode(); return result; } }