为什么List.Contains不像我期望的那样工作?

为什么这个程序打印“未添加”而我认为它应该打印“添加”?

using System; using System.Collections.Generic; class Element { public int id; public Element(int id) { this.id = id; } public static implicit operator Element(int d) { Element ret = new Element(d); return ret; } public static bool operator ==(Element e1, Element e2) { return (e1.id == e2.id); } public static bool operator !=(Element e1, Element e2) { return !(e1.id == e2.id); } } class MainClass { public static void Main(string[] args) { List element = new List(); element.Add(2); if(element.Contains(2)) Console.WriteLine("added"); else Console.WriteLine("not added"); } } 

Contains方法不使用==运算符。 问题是什么?

Contains方法不使用==运算符

不 – 它使用Equals ,你没有覆盖…所以你得到Equals的默认行为,这是检查引用标识。 你应该重写Equals(object)GetHashCode以使它们彼此一致 – 为了理智,与你的==重载一致。

我还建议实现IEquatableList将优先使用Equals(object) ,因为EqualityComparer.Default会适当地选择它。

哦,你的运算符重载也应该处理空引用。

我还强烈建议使用私有字段而不是公共字段,并使您的类型不可变 – 密封它并使id只读。 实现可变类型的相等可能导致奇怪的情况。 例如:

 Dictionary dictionary = new Dictionary(); Element x = new Element(10); dictionary[x] = "foo"; x.id = 100; Console.WriteLine(dictionary[x]); // No such element! 

这会发生,因为哈希代码会改变(至少在大多数实现中),因此字典下的哈希表甚至无法找到对已存在的同一对象的引用。

所以你的课程看起来像这样:

 internal sealed class Element : IEquatable { private readonly int id; public int Id { get { return id; } } public Element(int id) { this.id = id; } public static implicit operator Element(int d) { return new Element(d); } public static bool operator ==(Element e1, Element e2) { if (object.ReferenceEquals(e1, e2)) { return true; } if (object.ReferenceEquals(e1, null) || object.ReferenceEquals(e2, null)) { return false; } return e1.id == e2.id; } public static bool operator !=(Element e1, Element e2) { // Delegate... return !(e1 == e2); } public bool Equals(Element other) { return this == other; } public override int GetHashCode() { return id; } public override bool Equals(object obj) { // Delegate... return Equals(obj as Element); } } 

(顺便说一句,我不确定隐式转换的优点 – 我通常会远离那些,我自己。)

Contains方法不使用==运算符。 问题是什么?

那是正确的。

此方法[Contains]通过使用默认的相等比较器来确定相等性,由对象的T的IEquatable.Equals方法的实现(列表中的值的类型)定义。

http://msdn.microsoft.com/en-us/library/bhkz42b3(v=vs.110).aspx

您还需要覆盖Equals()。 注意当重载Equals()时,几乎总是正确地重写GetHashCode()。

覆盖EqualsGetHashCode如:

 class Element { public int id; protected bool Equals(Element other) { return id == other.id; } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; return Equals((Element) obj); } public override int GetHashCode() { return id; //or id.GetHashCode(); } //..... rest of the class 

请参阅: List.Contains Method

此方法通过使用默认的相等比较器来确定相等性,由对象的IEquatable.EqualsIEquatable.Equals方法的实现(列表中的值的类型)定义。