Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用重写的Equals()逻辑实现GetHashCode()的重写_C#_Overriding_Gethashcode - Fatal编程技术网

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) ...