C# 为什么';t列表。是否包含我期望的工作?
为什么这个程序打印“未添加”,而我认为它应该打印“添加”C# 为什么';t列表。是否包含我期望的工作?,c#,C#,为什么这个程序打印“未添加”,而我认为它应该打印“添加” 使用系统; 使用System.Collections.Generic; 类元素 { 公共int id; 公共元素(int-id) { this.id=id; } 公共静态隐式运算符元素(int d) { 元素ret=新元素(d); 返回ret; } 公共静态布尔运算符==(元素e1、元素e2) { 返回(e1.id==e2.id); } 公共静态布尔运算符!=(元素e1、元素e2) { 返回!(e1.id==e2.id); } } 类主类
使用系统;
使用System.Collections.Generic;
类元素
{
公共int id;
公共元素(int-id)
{
this.id=id;
}
公共静态隐式运算符元素(int d)
{
元素ret=新元素(d);
返回ret;
}
公共静态布尔运算符==(元素e1、元素e2)
{
返回(e1.id==e2.id);
}
公共静态布尔运算符!=(元素e1、元素e2)
{
返回!(e1.id==e2.id);
}
}
类主类
{
公共静态void Main(字符串[]args)
{
列表元素=新列表();
增加第(2)项;
if(元素包含(2))
控制台。写入线(“添加”);
其他的
Console.WriteLine(“未添加”);
}
}
Contains
方法不使用=
运算符. 有什么问题
Contains方法不使用==运算符. 有什么问题
这是正确的
此方法[Contains]使用默认的相等比较器确定相等,该比较器由对象对T(列表中的值类型)的IEquatable.Equals方法的实现定义
您还需要重写Equals()。注意,当重载Equals()时,重写GetHashCode()几乎总是正确的
Contains方法不使用==运算符
否-它使用等于
,您尚未覆盖它。。。因此,您将获得默认行为Equals
,即检查引用标识。您应该重写Equals(object)
和GetHashCode
以使它们彼此一致-并且为了理智起见,也要与您的=
重载一致
我还建议实现IEquatable
,它将优先于Equals(object)
,作为EqualityComparer。默认值将适当地选择它
哦,运算符重载也应该处理空引用
我还强烈建议使用私有字段而不是公共字段,并使您的类型不可变-将其密封并使id
为只读。为可变类型实现相等可能会导致奇怪的情况。例如:
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!
Dictionary Dictionary=newdictionary();
元素x=新元素(10);
字典[x]=“foo”;
x、 id=100;
Console.WriteLine(字典[x]);//没有这样的元素!
这是因为哈希代码会发生变化(至少在大多数实现中是如此),所以字典底层的哈希表甚至无法找到对已经在其中的同一对象的引用
所以你的班级看起来是这样的:
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);
}
}
内部密封类元素:IEquatable
{
私有只读int-id;
公共int Id{get{return Id;}}
公共元素(int-id)
{
this.id=id;
}
公共静态隐式运算符元素(int d)
{
返回新元素(d);
}
公共静态布尔运算符==(元素e1、元素e2)
{
if(object.ReferenceEquals(e1,e2))
{
返回true;
}
if(object.ReferenceEquals)(e1,null)||
object.ReferenceEquals(e2,null))
{
返回false;
}
返回e1.id==e2.id;
}
公共静态布尔运算符!=(元素e1、元素e2)
{
//代表。。。
返回!(e1==e2);
}
公共布尔等于(其他元素)
{
返回this==other;
}
公共覆盖int GetHashCode()
{
返回id;
}
公共覆盖布尔等于(对象对象对象)
{
//代表。。。
返回等于(obj作为元素);
}
}
(顺便说一句,我不确定隐式转换的优点是什么-我自己通常都不喜欢这些。)覆盖等于和获取hashcode
类似:
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
见:
此方法通过使用默认相等来确定相等
比较器,由对象的
IEquatable.Equals
T(列表中的值类型)的方法
忘记实现Equals和GetHashCode了吗?不值得为使用List而头疼。包含使用LINQ Where/First/Single+1作为演示问题的完整示例代码。假设id
唯一标识对象。这当然非常常见,但在某些情况下(例如,实体框架),id最初可能设置为0,直到稍后分配id为止(例如,当对象被持久化时)。我不确定Equals在这种情况下是否有意义,但如果这是OP的一种可能性,则需要考虑它。+1用于解释在字典或其他使用哈希代码的地方使用的对象发生变异的奇怪副作用。我不喜欢对非密封类型使用IEquatable
。即使实现了IEquatable
,仍然需要覆盖Equals(Object)
以实现语义正确性;除非IEquatable.Equals(T)
链接到Equals(Object)
[在这种情况下,接口将毫无用处],否则派生类将很难定义任何新的与等式相关的标准。顺便说一句,我也不喜欢在引用类型上重载==
。@supercat:同意密封-这就是为什么我将类密封为
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