C# 如何使用重写的Equals()逻辑实现GetHashCode()的重写
我有如下一些类,我已经为几乎所有的类实现了C# 如何使用重写的Equals()逻辑实现GetHashCode()的重写,c#,overriding,gethashcode,C#,Overriding,Gethashcode,我有如下一些类,我已经为几乎所有的类实现了Equals(Object)方法。但是我不知道如何编写GetHashCode()。就我在字典集合中将这些数据类型用作值类型而言,我认为应该重写GetHashCode() 1.我不知道如何用Equals(Object)逻辑实现GetHashCode() 2.有一些派生类,如果我为基类(Param)重写GetHashCode()和Equals(Object),是否仍然需要为child重写它 class Param { ... public I
Equals(Object)
方法。但是我不知道如何编写GetHashCode()
。就我在字典
集合中将这些数据类型用作值类型而言,我认为应该重写GetHashCode()
1.我不知道如何用Equals(Object)
逻辑实现GetHashCode()
2.有一些派生类,如果我为基类(Param
)重写GetHashCode()
和Equals(Object)
,是否仍然需要为child重写它
class Param
{
...
public Int16 id { get; set; }
public String name { get; set; }
...
public override bool Equals(object obj)
{
if ( obj is Param){
Param p = (Param)(obj);
if (id > 0 && p.id > 0)
return (id == p.id);
else if (name != String.Empty && p.name != String.Empty)
return (name.equals(p.name));
else
return object.ReferenceEquals(this, obj);
}
return false;
}
}
class Item
{
public int it_code { get; set; }
public Dictionary<String, Param> paramAr { get; set; }
...
public override bool Equals(Object obj)
{
Item im = new Item();
if (obj is Item)
im = (Item)obj;
else
return false;
if (this.it_code != String.Empty && im.it_code != String.Empty)
if (this.it_code.Equals(im.it_code))
return true;
bool reParams = true;
foreach ( KeyValuePair<String,Param> kvp in paramAr ){
if (kvp.Value != im.paramAr[kvp.Key]) {
reParams = false;
break;
}
}
return reParams;
}
}
class Order
{
public String or_code { get; set; }
public List <Item> items { get; set; }
...
public override bool Equals( Object obj ){
Order o = new Order();
if (obj is Order)
o = (Order)obj;
else
return false;
if (this.or_code != String.Empty && o.or_code != String.Empty)
if (this.or_code.Equals(o.or_code))
return true;
bool flag = true;
foreach( Item i in items){
if (!o.items.Contains(i)) {
flag = false;
break;
}
}
return flag;
}
}
类参数
{
...
公共Int16 id{get;set;}
公共字符串名称{get;set;}
...
公共覆盖布尔等于(对象对象对象)
{
if(obj为参数){
参数p=(参数)(obj);
如果(id>0&&p.id>0)
返回(id==p.id);
else if(name!=String.Empty&&p.name!=String.Empty)
返回(name.equals(p.name));
其他的
返回object.ReferenceEquals(this,obj);
}
返回false;
}
}
类项目
{
公共int it_代码{get;set;}
公共字典参数{get;set;}
...
公共覆盖布尔等于(对象对象对象)
{
项目im=新项目();
如果(obj是项目)
im=(项目)obj;
其他的
返回false;
if(this.it\u code!=String.Empty&&im.it\u code!=String.Empty)
if(this.it_code.等于(im.it_code))
返回true;
bool reParams=true;
foreach(参数中的KeyValuePair kvp){
if(kvp.Value!=im.paramAr[kvp.Key]){
重新编程=错误;
打破
}
}
返修;
}
}
阶级秩序
{
公共字符串或_代码{get;set;}
公共列表项{get;set;}
...
公共覆盖布尔等于(对象对象对象){
订单o=新订单();
如果(obj是订单)
o=(顺序)obj;
其他的
返回false;
if(this.or_code!=String.Empty&&o.or_code!=String.Empty)
如果(此或_代码等于(o或_代码))
返回true;
布尔标志=真;
foreach(项目中的项目i){
如果(!o.items.Contains(i)){
flag=false;
打破
}
}
返回标志;
}
}
编辑:
我得到这个警告:
警告:“项”覆盖对象。等于(对象o),但不覆盖
重写对象。GetHashCode()
我更喜欢乔希·布洛赫的便鞋 下面是
Param
类的示例
override GetHashCode(object obj)
{
unchecked
{
int hash = 17;
hash = hash * 23 + id.GetHashCode();
hash = hash * 23 + name.GetHashCode();
return hash;
}
}
此外,请查看以下链接:
用于hashcode计算的属性也应该是不可变的 首先,正如我认为您理解的,无论您在哪里实现
Equals
,都必须实现GetHashCode
。GetHashCode
的实现必须反映Equals
实现的行为,但它通常不使用它
请参阅-尤其是“实施者注意事项”
因此,如果您以项
实现等于
为例,您考虑的是id
和name
的值都会影响相等性。因此,这两种方法都必须有助于实现GetHashCode
关于如何为Item
实现GetHashCode
的示例如下(注意,您可能需要使其对可为空的name
字段具有弹性):
请参阅Eric Lippert关于GetHashCode
指南的博客文章
至于您是否需要在子类中重新实现GetHashCode
,如果您还重写了Equals
,那么根据第一点(也是主要点),这两个项的实现必须是一致的,如果Equals
认为两个项相等,那么它们必须从GetHashCode
返回相同的值
旁注:
作为对代码的性能改进(避免多次强制转换):
我相信在编写
GetHashCode
时,您需要考虑的唯一一点是,当两个对象相等时(通过调用Equals
),它们的哈希代码也必须相等。相反,如果两个散列码相等,这并不意味着对象本身相等(尽管它们可能相等)。每当您编写Equals
或GetHashCode
的自定义实现时,您都必须为另一个方法编写一些东西,以确保我上面解释的逻辑保持正确。Visual Studio现在可以帮助您完成这项工作。关于order
类,它只有一个id和一个列表,我无法使用其列表中的所有值来生成哈希代码。列表对象有一个GetHashCode
实现,可能足以满足您的需要。因为列表影响相等性,所以您必须在<代码> GetHashCode <代码>实现中考虑它。然而,再看看您的Equals
实现,您是在分层意义上使用它们的——如果ID匹配,那么无论对象的名称值如何,对象都是相等的。因此,GetHashCode
实现需要与我最初的建议不同;我还没弄明白怎么。。。(然而)@rene如果你在Equals中就是这么做的,那么是的,这正是你需要做的。@KAJ列表的GetHashCode将基于列表的引用,而不是它的内容。具有相同项的两个不同列表不一定具有相同的哈希代码。现在,如果您将订单的相等定义为仅基于订单代码,而不是基于项目,那么这些问题就会消失。Equals只需比较订单代码,getHashCode只需返回订单代码的哈希代码。如果
public override GetHashCode()
{
return id.GetHashCode() ^ name.GetHashCode();
}
if ( obj is Param){
Param p = (Param)(obj);
Param p = obj as Param;
if (p != null) ...