使用Linq与自定义IEqualityComparer相交

长话短说:我有2个对象集合。 一个包含好的值(让我们称之为“好”),其他默认值(先生“默认”)。 我希望联盟的相交在良好和默认之间,以及默认。 换句话说:相交(联合(良好,默认),默认)。 有人可能认为它解析为默认值,但这里是棘手的:我使用自定义IEqualityComparer。

我得到了以下课程:

class MyClass { public string MyString1; public string MyString2; public string MyString3; } class MyEqualityComparer : IEqualityComparer { public bool Equals(MyClass item1, MyClass item2) { if(item1 == null && item2 == null) return true; else if((item1 != null && item2 == null) || (item1 == null && item2 != null)) return false; return item1.MyString1.Equals(item2.MyString1) && item1.MyString2.Equals(item2.MyString2); } public int GetHashCode(MyClass item) { return new { item.MyString1, item.MyString2 }.GetHashCode(); } } 

以下是我的collections品Good和Default集合的特征:

默认值:它是一个很大的集合,包含所有想要的{MyString1,MyString2}对,但是你可以猜测,MyString3值是默认值。

好:它是一个较小的集合,主要包含默认集合中的项目,但具有一些好的MyString3值。 它还有一些{MyString1,MyString2},它们位于想要的集合之外。

我想要做的是:只获取Good中默认的项目,但将Default中的其他项目添加到默认项目中。

这是我认为最好的尝试:

 HalfWantedResult = Good.Union(Default, new MyEqualityComparer()); WantedResult= HalfWantedResult.Intersect(Good, new MyEqualityComparer()); 

我教它应该有用,但我得到的结果基本上只是好的{MyString1,MyString2}对设置,但都来自默认设置,所以我有所有的默认值。 我也试过切换最后一个Intersect的Default和Good,但是得到了相同的结果。

首先,这是错误的:

 public bool Equals(MyClass item1, MyClass item2) { return GetHashCode(item1) == GetHashCode(item2); } 

如果哈希码是不同的,确定相应的2个项目是不同的,但如果它们相等则不能保证相应的2个项目是相等的。

所以这是正确的Equals实现:

 public bool Equals(MyClass item1, MyClass item2) { if(object.ReferenceEquals(item1, item2)) return true; if(item1 == null || item2 == null) return false; return item1.MyString1.Equals(item2.MyString1) && item1.MyString2.Equals(item2.MyString2); } 

Slacks建议 (期待我)代码如下:

 var Default = new List { new MyClass{MyString1="A",MyString2="A",MyString3="-"}, new MyClass{MyString1="B",MyString2="B",MyString3="-"}, new MyClass{MyString1="X",MyString2="X",MyString3="-"}, new MyClass{MyString1="Y",MyString2="Y",MyString3="-"}, new MyClass{MyString1="Z",MyString2="Z",MyString3="-"}, }; var Good = new List { new MyClass{MyString1="A",MyString2="A",MyString3="+"}, new MyClass{MyString1="B",MyString2="B",MyString3="+"}, new MyClass{MyString1="C",MyString2="C",MyString3="+"}, new MyClass{MyString1="D",MyString2="D",MyString3="+"}, new MyClass{MyString1="E",MyString2="E",MyString3="+"}, }; var wantedResult = Good.Intersect(Default, new MyEqualityComparer()) .Union(Default, new MyEqualityComparer()); // wantedResult: // AA + // BB + // XX - // YY - // ZZ - 

您需要检查实际的相等性,而不仅仅是哈希码相等。

GetHashCode()不是(也不可能GetHashCode()是无冲突的,这就是首先需要Equals方法的原因。

此外,您可以通过写作更简单地完成这项工作

 WantedResult = Good.Concat(Default).Distinct(); 

Distinct方法将返回每对重复项的第一项,因此这将返回所需的结果。

编辑 :那应该是

 WantedResult = Good.Intersect(Default, new MyEqualityComparer()) .Union(Default, new MyEqualityComparer());