跨进程/平台的字符串列表的一致HashCode

时间:2016-06-17 11:32:22

标签: c#

我看了下面的问题:

Good GetHashCode() override for List of Foo objects respecting the order

并问Jon Skeet以下内容: Good GetHashCode() override for List of Foo objects respecting the order

" @JonSkeet该解决方案是否与多个AppDomain中的字符串列表产生一致的结果?我有一个WCF服务器,其中来自各种平台(XP,Vista,Win7或不同的.Net Frameworks 3.5及更高版本)的多个应用程序可以连接,在所有这些情况下我需要从字符串列表中获得一致的哈希码就是这种情况?如果不是,我将如何实现这一目标?"

他的回答: " @RandRandom:你不应该使用GetHashCode - 它并不意味着在不同的进程中保持一致。你应该使用像SHA-256这样的东西。 "

不确定他提出的答案是如何实现的,所以为了不在评论区域提出详细的问题,我决定创建一个新问题。

假设您有以下列表:

var fooList = new List<string>()
{
    "",
    "StatAccount",
    "Value",
    "9900000701",
    "P1",
    "3",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "VFE-Lage.xlsx",
    "",
    "",
    "False",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
};

现在我需要一个比检查SequenceEquality更容易/更快比较的hashCode,我的列表是永久不变的。

我的班级看起来像这样:

public class Foo
{
    private List<string> _fooList = new List<string>();
    private int _fooListHashCode;

    public List<string> FooList
    {
        get
        {
            return _fooList;
        }
        set
        {
            _fooList = value;
            _fooListHashCode = GetListsHashCode(value);
        }
    }

    public static int GetListsHashCode(List<string> list)
    {
        //return hashCode...
        return 0;
    }

    public override int GetHashCode()
    {
        return _fooListHashCode;
    }

    public override bool Equals(object obj)
    {
        var foo = obj as Foo;
        if (foo == null)
            return false;

        return this._fooListHashCode == foo._fooListHashCode;
    }
}

2 个答案:

答案 0 :(得分:2)

这应该可以用于使用SHA256哈希比较两个字符串列表。

    private bool CompareLists(IEnumerable<string> value1, IEnumerable<string> value2)
    {
        // First convert lists to single strings
        var encoder = new UTF8Encoding();
        var hash = new SHA256CryptoServiceProvider();
        var sb1 = new StringBuilder();
        var sb2 = new StringBuilder();

        foreach (var item in value1)
        {
            sb1.Append(item);
        }

        foreach (var item in value2)
        {
            sb2.Append(item);
        }

        // Then hash and compare
        return Convert.ToBase64String(hash.ComputeHash(encoder.GetBytes(sb1.ToString()))) ==
               Convert.ToBase64String(hash.ComputeHash(encoder.GetBytes(sb2.ToString())));
    }

由于你的主列表是不可变的,你应该为它计算一次哈希并存储它,这会使这个方法更高效。可能有更好的方法,但这应该有效。

注意:要使此方法返回true,两个列表必须完全相同;相同数量的字符串,相同的字符串(包括大小写),顺序相同。

答案 1 :(得分:1)

根据我之前回答的评论:

    private int GetHashCode(IEnumerable<string> value)
    {
        var encoder = new UTF8Encoding();
        var hash = new SHA256CryptoServiceProvider();
        var sb = new StringBuilder();

        foreach (var item in value)
        {
            sb.Append(item);
        }

        return
            Convert.ToInt32(
                new Rfc2898DeriveBytes(sb.ToString(),
                    hash.ComputeHash(encoder.GetBytes(sb.ToString()))).GetBytes(4));
    }