字符串的哈希码在 .NET Core 2.1 中被破坏,但在 2.0 中有效
Hash code of string is broken in .NET Core 2.1, but works in 2.0
我最近将我的一个项目从 .NET Core 2.0 升级到了 .NET Core 2.1。这样做之后,我的几个测试开始失败。
缩小范围后,我发现在 .NET Core 2.1 中,无法使用具有字符串排序比较选项的文化感知比较器来计算字符串的哈希码。
我创建了一个重现我的问题的测试:
[TestMethod]
public void Can_compute_hash_code_using_invariant_string_sort_comparer()
{
var compareInfo = CultureInfo.InvariantCulture.CompareInfo;
var stringComparer = compareInfo.GetStringComparer(CompareOptions.StringSort);
stringComparer.GetHashCode("test"); // should not throw!
}
我已经在几个框架上对其进行了测试,结果如下:
- .NET Core 2.0: ✔ 通过
- .NET 核心 2.1:✖ 失败
- .NET Framework 4.7:✖ 失败
- .NET Framework 4.6.2:✖ 失败
失败时 CompareInfo.GetHashCodeOfString
抛出 ArgumentException
说:
Value of flags is invalid
现在,回答我的问题:
为什么计算哈希码时不允许使用CompareOptions.StringSort
?
为什么在 .NET Core 2.0 中允许它?`
据我了解CompareOptions.StringSort
只影响字符串的相对排序顺序,不应该影响哈希码计算。 MSDN 说:
StringSort Indicates that the string comparison must use the string sort algorithm. In a string sort, the hyphen and the apostrophe, as well as other nonalphanumeric symbols, come before alphanumeric characters.
corefx 团队 confirmed 这是 .NET Core 2.1 中的错误,也是 4.6+ 的完整 .NET Framework 中的错误。
他们也承认很难在完整的框架中改变这种行为,因此可能会考虑在 .NET Core 2.1+ 中保持这种行为,以保持 .NET Core 和完整框架之间的一致性。
一个可能的解决方法是使用这样的 class:
internal sealed class CultureAwareStringSortComparer : StringComparer
{
public CultureAwareStringSortComparer(
CompareInfo compareInfo,
CompareOptions options = CompareOptions.StringSort)
{
Requires.ArgNotNull(compareInfo, nameof(compareInfo));
this.SortComparer = compareInfo.GetStringComparer(options);
this.HashCodeComparer = compareInfo.GetStringComparer(
options & ~CompareOptions.StringSort);
}
internal StringComparer SortComparer { get; }
internal StringComparer HashCodeComparer { get; }
public override int Compare(string x, string y) => this.SortComparer.Compare(x, y);
public override bool Equals(string x, string y) => this.SortComparer.Equals(x, y);
public override int GetHashCode(string obj) => this.HashCodeComparer.GetHashCode(obj);
}
我最近将我的一个项目从 .NET Core 2.0 升级到了 .NET Core 2.1。这样做之后,我的几个测试开始失败。
缩小范围后,我发现在 .NET Core 2.1 中,无法使用具有字符串排序比较选项的文化感知比较器来计算字符串的哈希码。
我创建了一个重现我的问题的测试:
[TestMethod]
public void Can_compute_hash_code_using_invariant_string_sort_comparer()
{
var compareInfo = CultureInfo.InvariantCulture.CompareInfo;
var stringComparer = compareInfo.GetStringComparer(CompareOptions.StringSort);
stringComparer.GetHashCode("test"); // should not throw!
}
我已经在几个框架上对其进行了测试,结果如下:
- .NET Core 2.0: ✔ 通过
- .NET 核心 2.1:✖ 失败
- .NET Framework 4.7:✖ 失败
- .NET Framework 4.6.2:✖ 失败
失败时 CompareInfo.GetHashCodeOfString
抛出 ArgumentException
说:
Value of flags is invalid
现在,回答我的问题:
为什么计算哈希码时不允许使用
CompareOptions.StringSort
?为什么在 .NET Core 2.0 中允许它?`
据我了解CompareOptions.StringSort
只影响字符串的相对排序顺序,不应该影响哈希码计算。 MSDN 说:
StringSort Indicates that the string comparison must use the string sort algorithm. In a string sort, the hyphen and the apostrophe, as well as other nonalphanumeric symbols, come before alphanumeric characters.
corefx 团队 confirmed 这是 .NET Core 2.1 中的错误,也是 4.6+ 的完整 .NET Framework 中的错误。
他们也承认很难在完整的框架中改变这种行为,因此可能会考虑在 .NET Core 2.1+ 中保持这种行为,以保持 .NET Core 和完整框架之间的一致性。
一个可能的解决方法是使用这样的 class:
internal sealed class CultureAwareStringSortComparer : StringComparer
{
public CultureAwareStringSortComparer(
CompareInfo compareInfo,
CompareOptions options = CompareOptions.StringSort)
{
Requires.ArgNotNull(compareInfo, nameof(compareInfo));
this.SortComparer = compareInfo.GetStringComparer(options);
this.HashCodeComparer = compareInfo.GetStringComparer(
options & ~CompareOptions.StringSort);
}
internal StringComparer SortComparer { get; }
internal StringComparer HashCodeComparer { get; }
public override int Compare(string x, string y) => this.SortComparer.Compare(x, y);
public override bool Equals(string x, string y) => this.SortComparer.Equals(x, y);
public override int GetHashCode(string obj) => this.HashCodeComparer.GetHashCode(obj);
}