为什么List.Contains不能按我期望的那样工作? [英] Why doesn't List.Contains work as I expect?
问题描述
为什么我认为该程序应该打印未添加",但为什么打印未添加"?
Why does this program print "not added" while I think it should print "added"?
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> element = new List<Element>();
element.Add(2);
if(element.Contains(2))
Console.WriteLine("added");
else
Console.WriteLine("not added");
}
}
包含
方法不使用 ==
运算符.有什么问题吗?
The Contains
method does not use the ==
operator. What is the problem?
推荐答案
Contains方法不使用==运算符
The Contains method does not use the == operator
否-它使用的是 Equals
,您没有对其进行覆盖...因此您将获得默认的行为,即 Equals
,用于检查参考身份反而.您应该覆盖 Equals(object)
和 GetHashCode
以便彼此保持一致-并且出于理智的考虑,也应与您的 ==
重载保持一致.
No - it uses Equals
, which you haven't overridden... so you're getting the default behaviour of Equals
, which is to check for reference identity instead. You should override Equals(object)
and GetHashCode
to be consistent with each other - and for sanity's sake, consistent with your ==
overload too.
我还建议实现 IEquatable< Element>
, List< Element>
优先于 Equals(object)
使用,作为 EqualityComparer< T>.默认
将其适当地提取.
I'd also recommend implementing IEquatable<Element>
, which List<Element>
will use in preference to Equals(object)
, as EqualityComparer<T>.Default
picks it up appropriately.
哦,您的运算符重载也应该处理空引用.
Oh, and your operator overloads should handle null references, too.
我还要强烈建议使用私有字段而不是公共字段,并使您的类型不可变-密封它并使 id
为只读.对可变类型实现相等可能会导致奇怪的情况.例如:
I'd also strongly recommend using private fields instead of public ones, and making your type immutable - seal it and make id
readonly. Implementing equality for mutable types can lead to odd situations. For example:
Dictionary<Element, string> dictionary = new Dictionary<Element, string>();
Element x = new Element(10);
dictionary[x] = "foo";
x.id = 100;
Console.WriteLine(dictionary[x]); // No such element!
之所以会这样,是因为哈希码会发生变化(至少在大多数实现中),因此字典下的哈希表甚至无法找到对已经存在的 same 对象的引用.在那里.
This would happen because the hash code would change (at least under most implementations), so the hash table underlying the dictionary wouldn't be able to find even a reference to the same object that's already in there.
所以您的课程看起来像这样:
So your class would look something like this:
internal sealed class Element : IEquatable<Element>
{
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);
}
}
(顺便说一下,我不确定隐式转换的优点-我通常会远离那些隐含转换.)
(I'm not sure about the merit of the implicit conversion, by the way - I typically stay away from those, myself.)
这篇关于为什么List.Contains不能按我期望的那样工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!