Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/285.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# 是否应为IEquatable实现GetHashCode<;T>;关于可变类型?_C#_Immutability_Mutable_Gethashcode_Iequatable - Fatal编程技术网

C# 是否应为IEquatable实现GetHashCode<;T>;关于可变类型?

C# 是否应为IEquatable实现GetHashCode<;T>;关于可变类型?,c#,immutability,mutable,gethashcode,iequatable,C#,Immutability,Mutable,Gethashcode,Iequatable,我正在实现IEquatable,在可变类上的GetHashCode覆盖上,我很难找到一致意见 以下资源都提供了一个实现,其中GetHashCode将在对象的生命周期内返回不同的值(如果对象发生更改): 但是,声明不应该为可变类型实现GetHashCode,因为如果对象是集合的一部分,它可能会导致不良行为(这也是我的理解) 有趣的是,实现的GetHashCode仅使用不可变属性,这符合我的理解。但我不明白为什么其他资源没有涵盖这一点。他们完全错了吗 如果一个类型根本没有不可变的属性,那么

我正在实现
IEquatable
,在可变类上的
GetHashCode
覆盖上,我很难找到一致意见

以下资源都提供了一个实现,其中
GetHashCode
将在对象的生命周期内返回不同的值(如果对象发生更改):

但是,声明不应该为可变类型实现
GetHashCode
,因为如果对象是集合的一部分,它可能会导致不良行为(这也是我的理解)

有趣的是,实现的
GetHashCode
仅使用不可变属性,这符合我的理解。但我不明白为什么其他资源没有涵盖这一点。他们完全错了吗

如果一个类型根本没有不可变的属性,那么当我重写
Equals(object)
时,编译器会警告说
GetHashCode
丢失。在这种情况下,我应该实现它并只调用
base.GetHashCode()
还是只禁用编译器警告,或者我是否遗漏了一些内容,并且
GetHashCode
应该始终被覆盖和实现?事实上,如果建议不应该为可变类型实现
GetHashCode
,为什么还要为不可变类型实现呢?与默认的
GetHashCode
实现相比,它仅仅是为了减少冲突,还是实际上添加了更具体的功能

总结一下我的问题,我的难题是在可变对象上使用
GetHashCode
,这意味着如果对象上的属性发生变化,它可以在对象的生命周期内返回不同的值。但不使用它意味着,比较可能等价的对象的好处将失去,因为它将始终返回唯一的值,因此集合将始终返回使用
Equals
进行操作


打印完这个问题后,在“类似问题”框中弹出,似乎是针对同一主题。答案似乎很明确,在
GetHashCode
实现中只应使用不可变属性。如果没有,那就不要写了<代码>字典仍能正常工作,尽管性能不是O(1)。

这取决于您所说的
集合类型。对于我的回答,我假设您谈论的是基于
哈希表
集合
,特别是.NET
字典
计算

因此,确定如果修改
(假设
是一个进行自定义
哈希代码
计算的类)将发生什么的最佳方法是查看.NET源代码。从.NET源代码中,我们可以看到您的
键值对
现在被包装到
条目
结构中,该结构携带
哈希代码
,该哈希代码是根据您的值的
加法
计算的。这意味着,如果在添加密钥后更改
HashCode
值,它将无法在
字典中找到值

证明它的代码:

    static void Main()
    {
        var myKey = new MyKey { MyBusinessKey = "Ohai" };
        var dic = new Dictionary<MyKey, int>();
        dic.Add(myKey, 1);
        Console.WriteLine(dic[myKey]);
        myKey.MyBusinessKey = "Changing value";
        Console.WriteLine(dic[myKey]); // Key Not Found Exception.
    }

    public class MyKey
    {
        public string MyBusinessKey { get; set; }
        public override int GetHashCode()
        {
            return MyBusinessKey.GetHashCode();
        }
    }
static void Main()
{
var myKey=new myKey{MyBusinessKey=“Ohai”};
var dic=新字典();
dic.Add(myKey,1);
控制台写入线(dic[myKey]);
myKey.MyBusinessKey=“更改值”;
Console.WriteLine(dic[myKey]);//找不到键异常。
}
公共类MyKey
{
公共字符串MyBusinessKey{get;set;}
公共覆盖int GetHashCode()
{
返回MyBusinessKey.GetHashCode();
}
}

来回答你的问题。您希望有不可变的值,您的
hashcode
计算基于这些值


另一点,如果不重写
GetHashCode
,则自定义类的
hashcode
将基于
对象的引用。因此,对于基础值相同的不同对象返回相同的
hashcode
的担忧可以通过
重写GetHashCode
方法并根据业务键计算
hashcode
来缓解。例如,您有两个字符串属性,要计算hashcode,您需要
concat
strings
并调用base
string
GetHashCode
方法。这将保证对于
对象的相同基础值,您将获得相同的
hashcode
,这取决于您所谈论的
集合类型。对于我的回答,我假设您谈论的是基于
哈希表
集合
,特别是.NET
字典
计算

因此,确定如果修改
(假设
是一个进行自定义
哈希代码
计算的类)将发生什么的最佳方法是查看.NET源代码。从.NET源代码中,我们可以看到您的
键值对
现在被包装到
条目
结构中,该结构携带
哈希代码
,该哈希代码是根据您的值的
加法
计算的。这意味着,如果在添加密钥后更改
HashCode
值,它将无法在
字典中找到值

证明它的代码:

    static void Main()
    {
        var myKey = new MyKey { MyBusinessKey = "Ohai" };
        var dic = new Dictionary<MyKey, int>();
        dic.Add(myKey, 1);
        Console.WriteLine(dic[myKey]);
        myKey.MyBusinessKey = "Changing value";
        Console.WriteLine(dic[myKey]); // Key Not Found Exception.
    }

    public class MyKey
    {
        public string MyBusinessKey { get; set; }
        public override int GetHashCode()
        {
            return MyBusinessKey.GetHashCode();
        }
    }
static void Main()
{
var myKey=new myKey{MyBusinessKey=“Ohai”};
var dic=新字典();
dic.Add(myKey,1);
控制台写入线(dic[myKey]);
myKey.MyBusinessKey=“更改值”;
Console.WriteLine(dic[myKey]);//找不到键异常。
}
公共类MyKey
{
公共字符串MyBusinessKey
class ThrowHasCode: IEquatable<ThrowHasCode>
{
    public int SomeVariable;
    public virtual Equals(ThrowHasCode other)
    {
        return other.SomeVariable == SomeVariable;
    }

    public override int GetHashCode()
    {
        throw new ApplicationException("this class does not support GetHashCode and should not be used as a key for a dictionary");
    }
}