问题:
当我对一个正确实现IEquatable
并重写GetHashCode
的类的IEnumerable<T>
使用Contains()
时,它返回false。如果我将匹配目标包装在列表中并执行Intersect()
,则匹配正常工作。我更喜欢使用Contains()
。
关于MSDN上的IEnumerable.Contains()
:
使用默认的相等比较器将元素与指定值进行比较
关于EqualityComparer<T>.Default
属性来自MSDN:
据我所知,在我的类上实现IEquatable应该意味着默认比较器在尝试查找匹配项时使用Equals方法。我想使用Equals,因为我希望只有一种方式可以使两个对象相同,我不希望开发人员记住要放入策略。
我觉得奇怪的是,如果我将匹配目标包装在List中,然后执行Intersect,那么匹配就会被正确找到。
我错过了什么?我也需要创建一个相等比较器吗,就像MSDN文章中所述?MSDN建议拥有IEquatable就足够了,它会为我包装它。
示例控制台应用程序:
注意:
GetHashCode()
来自 Jon Skeet 这里。using System;
using System.Collections.Generic;
using System.Linq;
namespace ContainsNotDoingWhatIThoughtItWould
{
class Program
{
public class MyEquatable : IEquatable<MyEquatable>
{
string[] tags;
public MyEquatable(params string[] tags)
{
this.tags = tags;
}
public bool Equals(MyEquatable other)
{
if (other == null)
{
return false;
}
if (this.tags.Count() != other.tags.Count())
{
return false;
}
var commonTags = this.tags.Intersect(other.tags);
return commonTags.Count() == this.tags.Count();
}
public override int GetHashCode()
{
int hash = 17;
foreach (string element in this.tags.OrderBy(x => x))
{
hash = unchecked(hash * element.GetHashCode());
}
return hash;
}
}
static void Main(string[] args)
{
// Two objects for the search list
var a = new MyEquatable("A");
var ab = new MyEquatable("A", "B");
IEnumerable<MyEquatable> myList = new MyEquatable[]
{
a,
ab
};
// This is the MyEquatable that we want to find
var target = new MyEquatable("A", "B");
// Check that the equality and hashing works
var isTrue1 = target.GetHashCode() == ab.GetHashCode();
var isTrue2 = target.Equals(ab);
var isFalse1 = target.GetHashCode() == a.GetHashCode();
var isFalse2 = target.Equals(a);
// Why is this false?
var whyIsThisFalse = myList.Contains(target);
// If that is false, why is this true?
var wrappedChildTarget = new List<MyEquatable> { target };
var thisIsTrue = myList.Intersect(wrappedChildTarget).Any();
}
}
}