对于标题的简略表述我表示抱歉,但实际标题会过长。以下是完整标题:重写
我预先道歉,这不是一个 “X是什么”类型的问题,更像是“我发现了X,我是否遗漏了些东西?”这类问题。
因此,请考虑以下内容:
我知道警告CS0659的原因是“类重写了Object.Equals(object o),但没有重写Object.GetHashCode()”。我不同意这些理由,因为
然而,当您可以考虑到需要的警告但未收到该警告时,就会出现问题。
上面的
有人知道其中原因吗?
我有什么漏洞吗?
可能需要一些配置窍门才能从编译器那里得到警告吗?
我必须以某种奇怪的方式声明我的类,例如
缺少警告的正当理由吗?
编辑:
到目前为止,已经有了一些答案,它们基本上都陈述了同样的事情:没有警告,因为没有违反
女士们先生们,你们错过了要点。
(或者我应该说是我道歉没有让这一点更清楚。)
支持缺少此警告的“无违反契约”论点与试图支持其他警告的缺席(例如“事件从未使用”)基本相同。基于声明事件并从未使用它不违反任何协议的原因来支持缺少此类警告,并没有多大意义。
首先,如果我通过声明事件并从未使用它来违反某些契约,那么我期望得到一个错误,而不是一个警告。
但是最重要的是,通过声明事件并从未使用它是一个严重而隐蔽的错误,所以需要一个警告,无论是否存在合同。
实际上,确实有一个警告!
它是CS0067 “事件'{0}'从未使用”。
看到吗?警告不需要违反任何契约。
因此,该论点已经被打破了。
还有什么其他论点吗?
重写Equals()
而没有重写GetHashCode()
时为什么会有警告,而重写GetHashCode()
而没有重写Equals()
却不会有警告?
我预先道歉,这不是一个 “X是什么”类型的问题,更像是“我发现了X,我是否遗漏了些东西?”这类问题。因此,请考虑以下内容:
class A
{
public override bool Equals( object other ) => true; //warning CS0659
}
class B
{
public override int GetHashCode() => 42; //No warning
}
我知道警告CS0659的原因是“类重写了Object.Equals(object o),但没有重写Object.GetHashCode()”。我不同意这些理由,因为
Equals()
对于可变类来说是完全可行的,而这种类当然不能用作哈希映射中的键,因此必须没有GetHashCode()
,但我的反驳无关紧要,并且在任何情况下,接收到你不需要的警告永远不是问题,因为您可以始终将其禁用。然而,当您可以考虑到需要的警告但未收到该警告时,就会出现问题。
上面的
类B
演示了这个问题。覆盖GetHashCode()
而没有同时覆写Equals()
几乎肯定是一个严重的错误,但却没有任何警告。既不是C#编译器,也不是ReSharper。有人知道其中原因吗?
我有什么漏洞吗?
可能需要一些配置窍门才能从编译器那里得到警告吗?
我必须以某种奇怪的方式声明我的类,例如
public sealed albino
之类的事情吗?缺少警告的正当理由吗?
编辑:
到目前为止,已经有了一些答案,它们基本上都陈述了同样的事情:没有警告,因为没有违反
GetHashCode()
和Equals()
的契约。女士们先生们,你们错过了要点。
(或者我应该说是我道歉没有让这一点更清楚。)
支持缺少此警告的“无违反契约”论点与试图支持其他警告的缺席(例如“事件从未使用”)基本相同。基于声明事件并从未使用它不违反任何协议的原因来支持缺少此类警告,并没有多大意义。
首先,如果我通过声明事件并从未使用它来违反某些契约,那么我期望得到一个错误,而不是一个警告。
但是最重要的是,通过声明事件并从未使用它是一个严重而隐蔽的错误,所以需要一个警告,无论是否存在合同。
实际上,确实有一个警告!
它是CS0067 “事件'{0}'从未使用”。
看到吗?警告不需要违反任何契约。
因此,该论点已经被打破了。
还有什么其他论点吗?
GetHashCode
方法返回一个常量而不重写Equals
方法实际上是功能上正确的,因为它不会为相等的实例返回不同的哈希码。但是这样做会导致基于哈希表的集合的查找性能下降到 O(n),效率非常低下。 - György KőszegGetHashCode
必须依赖于Equals
,而不是反过来。因此,当您更改Equals
逻辑时,还应该更改GetHashCode
,但是只要GetHashCode
仍然遵循Equals
规则,就可以更改GetHashCode
实现而不更改Equals
逻辑。 - Magnetron