首页 > 解决方案 > 字符串的哈希码在 .NET Core 2.1 中被破坏,但在 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!
}

我已经在几个框架上对其进行了测试,结果如下:

当失败时ArgumentException抛出一个CompareInfo.GetHashCodeOfString说:

标志值无效

现在,我的问题:

  1. CompareOptions.StringSort为什么计算哈希码时不允许使用?

  2. 为什么在 .NET Core 2.0 中允许使用它?`

据我了解,CompareOptions.StringSort仅影响字符串的相对排序顺序,不应影响哈希码计算。MSDN 说:

StringSort表示字符串比较必须使用字符串排序算法。在字符串排序中,连字符和撇号以及其他非字母数字符号位于字母数字字符之前。

标签: c#string.net-corehashcode

解决方案


corefx 团队已确认这是 .NET Core 2.1 以及 4.6+ 的完整 .NET Framework 中的一个错误。

他们还承认,在完整框架中很难改变这种行为,因此可能会考虑在 .NET Core 2.1+ 中保持原样,以保持 .NET Core 和完整框架之间的一致性。

一种可能的解决方法是使用这样的类:

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);
}

推荐阅读