为什么在重载相等运算符时期望覆盖GetHashCode和Equals?
重载Equals
运算符时未能覆盖GetHashCode
和Equals
会导致编译器产生警告。 为什么改变其中任何一个的实现是个好主意? 在阅读了Eric Lippert关于GetHashCode的博客文章之后,似乎可能没有很多有用的替代GetHashCode的基础实现,为什么编译器我鼓励你改变它?
我们假设你正在实现一个类。
如果你正在重载==
那么你正在生成一个具有值相等而不是引用相等的类型。
鉴于此,现在的问题是“在==
.Equals()
中实现引用相等的类和在==
值相等是多么令人满意?” 答案是“不太理想”。 这似乎是混淆的潜在根源。 (事实上,我现在为之工作的公司Coverity生产了一个缺陷发现工具,可以检查你是否因为参考等同而将价值平等混淆了。正因为这个原因,我只是在阅读规范时看到了它。你的问题!)
此外,如果你要有一个同时实现值和引用相等的类,通常的方法是重写Equals
并单独使用==
,而不是相反。
因此,鉴于您已超载==
,强烈建议您也重写Equals
。
如果要重写Equals
以产生值相等,则需要覆盖GetHashCode
以匹配,因为您知道是否已阅读我链接到的文章。
如果你在覆盖==
时不重写Equals()
,你将会遇到一些非常糟糕的代码。
你觉得这件事怎么样?
if (x == y) { if (!x.Equals(y)) throw new InvalidOperationException("Wut?"); }
这是一个例子。 鉴于此课程:
class Test { public int Value; public string Name; public static bool operator==(Test lhs, Test rhs) { if (ReferenceEquals(lhs, rhs)) return true; if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null)) return false; return lhs.Value == rhs.Value; } public static bool operator!=(Test lhs, Test rhs) { return !(lhs == rhs); } }
这段代码表现得很奇怪:
Test test1 = new Test { Value = 1, Name = "1" }; Test test2 = new Test { Value = 1, Name = "2" }; if (test1 == test2) Console.WriteLine("test1 == test2"); // This gets printed. else Console.WriteLine("test1 != test2"); if (test1.Equals(test2)) Console.WriteLine("test1.Equals(test2)"); else Console.WriteLine("NOT test1.Equals(test2)"); // This gets printed!
你不想要这个!
我的猜测是编译器从你的动作中获取线索,并决定由于你发现提供相等运算符的替代实现很重要,那么你可能希望对象相等性与你的新实现==
保持一致。 毕竟,你不希望两个相等的比较意味着完全不同的东西,否则你的程序即使在非常基本的层面也很难理解。 因此,编译器认为您也应该重新定义Equals
。
但是,一旦提供了替代实现Equals
,就需要修改GetHashCode
以保持与相等实现的一致性。 因此编译器会警告您实现可能不完整,并建议覆盖Equals
和GetHashCode
。
如果你没有重载Equals
方法,那么使用它可能会给你与运算符得到的结果不同。 就像,如果你重载=
整数…
int i = 1; (1 == 1) == (i.Equals(1))
可以评估为假。
出于同样的原因,您应该重新实现GetHashCode
方法,这样您就不会搞乱哈希表以及依赖于哈希比较的其他结构。
请注意,我说“可能”和“可能”,而不是“将”。 这些警告只是提醒您,如果您不遵循其建议,可能会发生意外情况。 否则你会得到错误而不是警告。
文档非常清楚:
GetHashCode方法可以由派生类型覆盖。 值类型必须覆盖此方法,以提供适合该类型的哈希函数,并在哈希表中提供有用的分布。 为了唯一性,哈希码必须基于实例字段或属性的值,而不是静态字段或属性。
用作Hashtable对象中的键的对象还必须覆盖GetHashCode方法,因为这些对象必须生成自己的哈希代码。 如果用作键的对象不提供GetHashCode的有用实现,则可以在构造Hashtable对象时指定哈希代码提供程序。 在.NET Framework 2.0版之前,哈希代码提供程序基于System.Collections.IHashCodeProvider接口。 从2.0版开始,哈希代码提供程序基于System.Collections.IEqualityComparer接口。
上述就是C#学习教程:为什么在重载相等运算符时期望覆盖GetHashCode和Equals?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/955466.html