Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.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# 如何为通过值进行比较的类编写一个好的GetHashCode()实现?_C#_Hash_Gethashcode_Consistent Hashing - Fatal编程技术网

C# 如何为通过值进行比较的类编写一个好的GetHashCode()实现?

C# 如何为通过值进行比较的类编写一个好的GetHashCode()实现?,c#,hash,gethashcode,consistent-hashing,C#,Hash,Gethashcode,Consistent Hashing,假设我们有这样一门课: class MyClass { public string SomeValue { get; set; } // ... } 现在,假设两个MyClass实例的SomeValue属性相等时,它们是相等的。因此,我覆盖了对象.Equals()和对象.GetHashCode()方法来表示它Object.GetHashCode()返回SomeValue.GetHashCode(),但同时我需要遵循以下规则: 如果一个对象的两个实例相等,则它们应返回相同的哈希

假设我们有这样一门课:

class MyClass
{
    public string SomeValue { get; set; }

    // ...
}
现在,假设两个
MyClass
实例的
SomeValue
属性相等时,它们是相等的。因此,我覆盖了
对象.Equals()
对象.GetHashCode()
方法来表示它
Object.GetHashCode()
返回
SomeValue.GetHashCode()
,但同时我需要遵循以下规则:

  • 如果一个对象的两个实例相等,则它们应返回相同的哈希代码
  • 哈希代码不应在整个运行时更改
  • 但是很明显,
    SomeValue
    可以更改,我们之前得到的哈希代码可能会变得无效

    我只能考虑使类不可变,但我想知道其他人在这种情况下会做什么


    在这种情况下你会怎么做?拥有这样一个类是否代表了设计决策中更微妙的问题?

    总合同规定,如果a.equals(B)为真,那么它们的哈希代码必须相同。如果A中的某个值发生更改,导致A.equals(B)不再为true,则A.GetHashCode()可以返回与以前不同的值。可变对象无法缓存GetHashCode(),必须在每次调用该方法时计算它

    本文提供了有关GetHashCode和可变性的详细指南:


    总合同规定,如果A.equals(B)为真,则它们的哈希代码必须相同。如果A中的某个值发生更改,导致A.equals(B)不再为true,则A.GetHashCode()可以返回与以前不同的值。可变对象无法缓存GetHashCode(),必须在每次调用该方法时计算它

    本文提供了有关GetHashCode和可变性的详细指南:


    您需要在可变性和GetHashCode之间进行选择,GetHashCode为'equal'对象返回相同的值。通常,当您认为您想要为可变对象实现“相等”时,您最终决定您有“相等的阴影”,并且实际上并不意味着Object.Equals相等

    在任何类型的数据结构中,将可变对象作为“键”对我来说都是一个巨大的危险信号。例如:

    MyObj a = new MyObj("alpha");
    MyObj b = new MyObj("beta");
    HashSet<MyObj> objs = new HashSet<MyObj>();
    objs.Add(a);
    objs.Add(b);
    // objs.Count == 2
    b.SomeValue = "alpha";
    // objs.Distinct().Count() == 1, objs.Count == 2
    
    MyObj a=新的MyObj(“α”);
    MyObj b=新的MyObj(“β”);
    HashSet objs=新HashSet();
    添加(a)项;
    添加(b)项;
    //objs.Count==2
    b、 SomeValue=“alpha”;
    //objs.Distinct().Count()==1,objs.Count==2
    

    我们严重违反了HashSet的合同。这是一个明显的例子,有一些微妙的例子。

    您需要在易变性和为“equal”对象返回相同值的GetHashCode之间进行选择。通常,当您认为您想要为可变对象实现“相等”时,您最终决定您有“相等的阴影”,并且实际上并不意味着Object.Equals相等

    在任何类型的数据结构中,将可变对象作为“键”对我来说都是一个巨大的危险信号。例如:

    MyObj a = new MyObj("alpha");
    MyObj b = new MyObj("beta");
    HashSet<MyObj> objs = new HashSet<MyObj>();
    objs.Add(a);
    objs.Add(b);
    // objs.Count == 2
    b.SomeValue = "alpha";
    // objs.Distinct().Count() == 1, objs.Count == 2
    
    MyObj a=新的MyObj(“α”);
    MyObj b=新的MyObj(“β”);
    HashSet objs=新HashSet();
    添加(a)项;
    添加(b)项;
    //objs.Count==2
    b、 SomeValue=“alpha”;
    //objs.Distinct().Count()==1,objs.Count==2
    
    我们严重违反了HashSet的合同。这是一个明显的例子,有一些微妙的例子。

    如果您的
    GetHashCode()
    依赖于某个可变值,那么每当值发生变化时,您就必须更改哈希值。否则你就违反了平等法

    如果您将对象放入
    哈希集
    或作为
    字典
    中的键,则在有人请求哈希时,哈希就不应更改。在这些情况下,您必须确保哈希代码只要存储在这样的容器中就不会被更改。这可以手动确保,只需在编程时处理此问题,也可以为对象提供一些
    Freeze()
    方法。如果调用此函数,则任何后续设置属性的尝试都会导致某种异常(然后还应提供一些
    Defrost()
    方法)。此外,您还将
    Freeze()
    方法的调用放入
    GetHashCode()
    实现中,因此您可以非常确定没有人会错误地更改冻结的对象

    还有最后一个提示:如果您需要更改这样一个容器中的对象,只需删除它,更改它(不要忘记解冻它),然后重新添加它。

    如果您的
    GetHashCode()
    依赖于某个可变值,那么每当值发生更改时,您必须更改哈希值。否则你就违反了平等法

    如果您将对象放入
    哈希集
    或作为
    字典
    中的键,则在有人请求哈希时,哈希就不应更改。在这些情况下,您必须确保哈希代码只要存储在这样的容器中就不会被更改。这可以手动确保,只需在编程时处理此问题,也可以为对象提供一些
    Freeze()
    方法。如果调用此函数,则任何后续设置属性的尝试都会导致某种异常(然后还应提供一些
    Defrost()
    方法)。此外,您还将
    Freeze()
    方法的调用放入
    GetHashCode()
    实现中,因此您可以非常确定没有人会错误地更改冻结的对象


    还有最后一个提示:如果你需要改变这样一个容器中的一个对象,只需移除它,改变它(别忘了解冻),然后再次添加它。

    显然。。。但是如果我们在哈希表中放入一个,然后更改
    SomeValue
    属性,我们就会遇到麻烦,因为哈希代码现在不同了。我想知道解决这个问题的方法是什么。我能想到的一个方法是使用不变性。是的,这是对可变性的限制。例如,在Java中,Set的文档中说:“注意:如果对象是可变的,必须非常小心