【问题标题】:StringComparer.InvariantCultureIgnoreCase Equals vs GetHashCode disagree for equal objectsStringComparer.InvariantCultureIgnoreCase Equals vs GetHashCode 不同意相等的对象
【发布时间】:2019-06-12 02:20:59
【问题描述】:

StringComparer.InvariantCultureIgnoreCase Equals 对于 "" 与 "\0" 返回 true,但 GetHashCode 对于两个字符串返回不同的值。这是一个错误吗?

var sc = StringComparer.InvariantCultureIgnoreCase;
string s1 = "";
string s2 = "\0";
Console.WriteLine( sc.Equals(s1, s2)  );
Console.WriteLine( sc.GetHashCode(s1) );
Console.WriteLine( sc.GetHashCode(s2) );

返回

True
0
-1644535362

我认为 GetHashCode 应该为“相等”字符串返回相同的值,所以这是一个错误吗?

【问题讨论】:

  • .net 的哪个版本?
  • 似乎是 .NET 中的一个错误。与 cmets 中的 mentioned 一样,IEqualityComparer<T>required 为它自己的 Equals() 返回 true 的字符串返回相等的哈希值。 InvariantCultureIgnoreCase 实现 IEqualityComparer<string>
  • 罪魁祸首似乎是零长度字符串的零散列,而不是 \0 本身的添加。当两个字符串都具有非零长度(例如"a""a\0")时,比较器似乎返回相等的哈希值。
  • MS 将问题关闭为不会修复。
  • 对于 .NET Framework,他们表示由于向后兼容性问题,他们不会修复它。对于 .NET Core,它已被标记为一个错误,希望有一个修复......或者至少解释了这种行为的原因。 (github.com/dotnet/corefx/issues/34662) 有一段时间了,但以防万一你想知道。

标签: c# .net


【解决方案1】:

这两个字符串不是按位相等的。它们有 2 种不同的长度。因此,哈希码算法在这里是合理的。

字符串比较算法在进行比较时必须忽略\0。我looked into the source:它正在做某种加/减比较算法来找出是否有不同。

GetHashCode 仅表示值可能相等,不一定相等。反之亦然,您可以覆盖任何类型的 == 运算符或 .Equals,并在哈希码不一致时生成 true

这里是GetHashCode。看起来它正在使用原始字节进行计算。

您可能偶然发现了 .NET 库中的一个不起眼的错误,但我猜这是一个边缘案例。

然后-您正在使用字符串比较器。不是string.Equals 方法或string.GetHashCode。注意Console.WriteLine("\0".Equals("")); 产生false

如果你想要一个字符串比较器让它同意,我相信StringComparer.OrdinalIgnoreCase 会做到这一点,因为它会单独查看每个字符,而不是对值进行排序。 它看起来两者都只是采用相同的字符比较方法。

【讨论】:

  • 这对于通用的string.GetHashCode() 来说是有意义的,但它是StringComparer.InvariantCultureIgnoreCase.GetHashCode(),它肯定必须为它自己认为相等的字符串返回相同的哈希值吗?
  • @GSerg 不一定。
  • 我不明白。在大规模比较中,Equals() 仅对具有相等哈希值的对调用,那么如何允许比较器为相等的字符串返回不相等的哈希值?
  • 反之亦然,您可以覆盖任何类型的== 运算符或.Equals,并在哈希码不一致时生成trueDocumentation 似乎不同意这一点:需要实现以确保如果Equals(T, T) 方法为xy 两个对象返回true,那么GetHashCode(T) 返回的值x 的方法必须等于 y 的返回值。
  • 方法签名不是接口契约的唯一部分。预期的行为也是契约的一部分,尽管 C# 没有提供在代码中表达这部分的方法。如果您违反了该规则,那么您就破坏了实施。
猜你喜欢
  • 1970-01-01
  • 2014-12-24
  • 2014-09-30
  • 2019-11-03
  • 2014-06-11
  • 2023-04-09
  • 2016-04-10
相关资源
最近更新 更多