【问题标题】:How to calculate JObject's unique Hashcode如何计算 JObject 的唯一 Hashcode
【发布时间】:2019-07-11 19:25:33
【问题描述】:

我想计算 Jobject 的唯一哈希码。所以基于so post 我正在使用JTokenEqualityComparer.GetHashCode(JToken token) 方法来计算哈希码

    [Fact]
    public void GetHashcode()
    {
        JTokenEqualityComparer comp = new JTokenEqualityComparer();

        // arrange
        var obj1 = new JObject();
        obj1.Add("FirstName", "foo");
        obj1.Add("LastName", "bar");

        var hashCode = comp.GetHashCode(obj1);
    }

但是,每次我运行此单元测试时,它都会创建不同的哈希码。所以看起来除了属性名称和属性值之外,它还使用其他东西来计算哈希码。

我在 ASP.NET 核心应用程序中使用此代码。它为具有相同属性和值的 JObject 创建唯一的哈希码,但是一旦应用程序池被回收,它就会为相同的 JObject 创建新的哈希码。

如何为具有相同属性和值的 JObject 创建唯一的哈希码?

因此,如果有 3 个 JObject 实例具有相同的属性和值,则它们的哈希码应该相同,而与计算哈希码的机器、时间和类无关。

【问题讨论】:

  • 我不确定是否可以不创建自己的哈希码实现。问题是,为什么您需要与 previous run 中相同的哈希码?在 .NET Core 中,哈希码计算算法被植入随机值。这就是为什么你会得到不同的哈希码(即使是纯字符串),请参阅this post 在该博客文章中,还有确定性哈希码的实现技巧 - 每次都相同。
  • 我有 JObjects 列表,我想比较它们以发现 JObjects 的百分比是相同的。所以基本上我需要每个作业的唯一(最好是整数或长整数)
  • 不确定您是否应该假设这一点。请参阅 Eric Lippert 的 Guidelines and rules for GetHashCode,其中指出,规则:GetHashCode 的消费者不能依赖它随着时间的推移或跨应用程序域而保持稳定
  • 实际上我无法在 .Net 完整框架上重现此内容;请参阅dotnetfiddle.net/s0ZE40,它每次运行时总是返回 -1347780462。字符串哈希码呢? "foo".GetHashCode() 在您的应用程序域和机器上是否稳定?...啊,我看到 previously linked article 说哈希码是在 .Net 核心版本构建中随机播种的。 (我认为在 .Net 完整框架调试版本中总是如此。)
  • 嗯,如果string.GetHashCode() 确实不稳定,您需要创建自己的(递归)版本的GetDeepHashCode()。请注意,JSON 对象被认为是无序的,因此JObject 的哈希码需要在属性顺序排列方面保持不变。 JContainer.ContentsHashCode() 只需将项目哈希码异或在一起即可。

标签: .net asp.net-core .net-core json.net hashcode


【解决方案1】:

你可以使用这样的东西。虽然我不确定,如果从 JSON 的角度来看它是确定的——例如,没有尝试使用数组。但我相信你将能够适应它。 :)

[Fact]
public void GetHashcode() {
    var o1 = new JObject();
    o1.Add("FirstName", "foo");
    o1.Add("LastName", "bar");

    var o2 = new JObject();
    o2.Add("Lorem", 123);
    o2.Add("Ipsum", DateTime.Now.Date);

    o1.Add("inner", o2);

    var hashCode = ComputeHashCode(o1);
}

private static int ComputeHashCode(JToken value)
{
    if (value is null)
    {
        return 0;
    }

    var queue = new Queue<JProperty>();
    foreach (JProperty prop in value)
    {
        queue.Enqueue(prop);
    }
    if (queue.Count == 0)
    {
        return 0;
    }

    int hash = 17;
    while (queue.Count > 0)
    {
        JProperty item = queue.Dequeue();
        if (item.Value.HasValues)
        {
            foreach (JProperty prop in item.Value)
            {
                queue.Enqueue(prop);
            }
        }
        else
        {
            // Hash code combination taken from here: https://stackoverflow.com/a/263416/8088324
            unchecked
            {
                hash = hash * 23 + ComputeHashCodeCore(item.Name);
                hash = hash * 23 + ComputeHashCodeCore(item.Value.ToString());
            }
        }
    }
    return hash;
}

// Stable hash code for string taken from here: https://stackoverflow.com/a/36845864/8088324
private static int ComputeHashCodeCore(string str)
{
    unchecked
    {
        int hash1 = 5381;
        int hash2 = hash1;

        for (int i = 0; i < str.Length && str[i] != '\0'; i += 2)
        {
            hash1 = ((hash1 << 5) + hash1) ^ str[i];
            if (i == str.Length - 1 || str[i + 1] == '\0')
                break;
            hash2 = ((hash2 << 5) + hash2) ^ str[i + 1];
        }

        return hash1 + (hash2 * 1566083941);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-12
    • 2014-07-23
    • 2012-09-25
    相关资源
    最近更新 更多