重载等于运算符时未能覆盖GetHashCode
和Equals
会导致编译器产生警告。为什么改变其中任何一个的实现是个好主意?在阅读Eric Lippert's blog post on GetHashCode后,似乎GetHashCode的基本实现可能没有太多有用的替代方案,为什么编译器我鼓励你改变它?
答案 0 :(得分:9)
假设您正在实施一个类。
如果您正在重载==
,那么您将生成一个值相等而非引用相等的类型。
鉴于此,现在的问题是“在.Equals()
中实现引用相等的类和==
中的值相等是多么令人满意?”答案是“不太理想”。这似乎是混淆的潜在根源。 (事实上,我现在为公司工作的公司Coverity生产了一个缺陷发现工具,可以检查你是否将价值平等与参考平等混淆,正是出于这个原因。巧合的是,当我看到它时,我只是在读它的规范。你的问题!)
此外,如果您要创建一个同时实现值和引用相等的类,通常的方法是覆盖Equals
并单独留下==
,而不是相反。
因此,鉴于您已超载==
,强烈建议您也覆盖Equals
。
如果您要覆盖Equals
以产生价值相等,则必需覆盖GetHashCode
以匹配,因为您知道如果您已阅读我关联的文章到。
答案 1 :(得分:3)
如果覆盖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!
你 NOT 想要这个!
答案 2 :(得分:1)
我的猜测是编译器从你的动作中获取线索,并决定由于你发现提供等于运算符的替代实现很重要,那么你可能希望对象相等与你的新实现保持一致{ {1}}。毕竟,你不希望两个相等的比较意味着完全不同的东西,否则你的程序即使在非常基础的层面上也很难理解。因此,编译器认为您也应该重新定义==
。
但是,一旦提供了替代实现Equals
,就需要修改Equals
以保持与相等实现的一致性。因此,编译器会警告您,您的实现可能不完整,并建议覆盖GetHashCode
和Equals
。
答案 3 :(得分:0)
如果您没有重载Equals
方法,那么使用它可能会给您与运营商获得的结果不同。比如,如果你为整数重载=
......
int i = 1;
(1 == 1) == (i.Equals(1))
可以评估为假。
出于同样的原因,你应该重新实现GetHashCode
方法,这样你就不会搞乱哈希表以及依赖哈希比较的其他结构。
注意我说“可能”和“可能”,而不是“会”。这些警告只是提醒您,如果您不遵循其建议,可能会发生意外情况。否则你会收到错误而不是警告。
答案 4 :(得分:0)
documentation对此很清楚:
GetHashCode方法可以被派生类型覆盖。值 类型必须覆盖此方法以提供哈希函数 适合该类型并在a中提供有用的分布 哈希表。为了唯一性,哈希码必须基于值 实例字段或属性而不是静态字段或 属性。
在Hashtable对象中用作键的对象也必须覆盖 GetHashCode方法因为那些对象必须生成自己的哈希 码。如果用作键的对象不提供有用的 实现GetHashCode,您可以指定哈希码提供程序 何时构造Hashtable对象。在.NET Framework之前 版本2.0,哈希代码提供程序基于 System.Collections.IHashCodeProvider接口。从版本开始 2.0,哈希码提供程序基于System.Collections.IEqualityComparer接口。