【问题标题】:Consistent HashCode for a List of String accross processes/platforms跨进程/平台的字符串列表的一致哈希码
【发布时间】:2016-06-17 11:32:21
【问题描述】:

我看了以下问题:

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

然后问乔恩·斯基特以下问题: Good GetHashCode() override for List of Foo objects respecting the order

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

他的回答: “@RandRandom:您不应该为此使用 GetHashCode - 它并不意味着在不同的进程中保持一致。您应该为此使用 SHA-256 之类的东西。”

不确定他提出的答案的实施情况如何,所以为了不在 cmets 领域提出详细问题,我决定创建一个新问题。

所以假设你有以下列表:

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

【问题讨论】:

    标签: c#


    【解决方案1】:

    这应该适用于使用 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,两个列表必须完全相同;相同数量的字符串,相同的字符串(包括大小写),以相同的顺序。

    【讨论】:

    • 如何将其转换为 int 以将其返回给 GetHashCode 方法?因为我需要这些对象的 HashSet 和字典。
    • 在这种情况下,我根本不会使用散列,我会使用 Rfc2898DeriveBytes 来获取一个 4 字节数组,您可以将其转换为 int。我会发布第二个答案。
    【解决方案2】:

    根据我之前的回答,根据 cmets:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-23
      • 2015-05-23
      • 1970-01-01
      • 2011-03-23
      • 2011-02-13
      • 2015-09-19
      相关资源
      最近更新 更多