【问题标题】:GetHashCode returns the same value for different objects. Is there any method to identify object by particular properties?GetHashCode 为不同的对象返回相同的值。有什么方法可以通过特定属性来识别对象吗?
【发布时间】:2019-05-31 16:40:21
【问题描述】:

我正在尝试创建一个哈希码方法。我有如下代码:

    private static object GetValue<T>(object item, string propertyName)
    {
        ParameterExpression arg = Expression.Parameter(item.GetType(), "x");
        Expression expr = Expression.Property(arg, propertyName);
        UnaryExpression unaryExpression = Expression.Convert(expr, typeof(object));
        var propertyResolver = Expression.Lambda<Func<T, object>>(unaryExpression, arg).Compile();
        return propertyResolver((T)item);
    }


    private static int GetHashCode<T>(T obj, List<string> columns)
    {
        unchecked
        {
            int hashCode = 17;

            for (var i = 0; i < columns.Count; i++)
            {
                object value = GetValue<T>(obj, columns[i]);
                var tempHashCode = value == null ? 0 : value.GetHashCode();
                hashCode = (hashCode * 23) + tempHashCode;
            }

            return hashCode;
        }
    }

    private static void TestHashCode()
    {
        var t1 = new { ID = (long)2044716, Type = "AE", Method = (short)1022, Index = 3 };
        var t2 = new { ID = (long)12114825, Type = "MEDAPE", Method = (short)1700, Index = 2 };

        var e1 = t1.GetHashCode();
        var e2 = t2.GetHashCode();

        var columns = new[] { "ID", "Type", "Method", "Index" }.ToList();
        var k1 = GetHashCode(t1, columns);
        var k2 = GetHashCode(t2, columns);
    }

e1值为-410666035,e2值为101205027。 k1 值为 491329214。k2 值为 491329214。

哈希码步骤:

hashCode = 17
tempHashCode = 2044716
哈希码 = 2045107
tempHashCode = 1591023428
哈希码 = 1638060889
tempHashCode = 66978814
哈希码 = -912326403
tempHashCode = 3
哈希码 = 491329214

k1 和 k2 怎么可能是同一个值?因为默认的 .net gethashcode 方法给出了两个不同的值。我想创建一个可以获取列列表的哈希码方法。我想通过特定属性创建一个哈希码。我正在尝试通过特定属性为对象获取唯一值。

如果 GetHashCode 不保证唯一值,我如何通过特定属性识别对象?

【问题讨论】:

  • 在调试代码时,对于每个输入,请在每个 for 循环迭代结束时共享 hashCode 的值。
  • for 方法的for 循环中,GetValue&lt;T&gt;() 调用返回什么类型和值?请编辑您的问题以包含类型 (GetType()) 和每次循环迭代的 value 变量的 ToString() 结果。
  • @Progman 类型和值很清楚。它们是在对象中定义的。
  • 您需要使用具有 Compare() 方法的 IEquatable,以便在哈希给出重复项时获取唯一值。请参阅:docs.microsoft.com/en-us/dotnet/api/…

标签: c# hashcode gethashcode


【解决方案1】:

我怀疑问题是由您的GetHashCode&lt;T&gt; 方法中的value.GetHashCode() 引起的。该值变量是那里的一个对象,我认为GetHashCode() 没有返回您所期望的。尝试调试以了解发生了什么。

您可能想尝试保留您的代码,但不要使用Object.GetHashCode(),而是使用RuntimeHelpers.GetHashCode()(来自命名空间System.Runtime.CompilerServices)。

完整参考:https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.runtimehelpers.gethashcode?redirectedfrom=MSDN&view=netframework-4.7.2#System_Runtime_CompilerServices_RuntimeHelpers_GetHashCode_System_Object_

祝你好运!

【讨论】:

    【解决方案2】:

    GetHashCode 返回一个依赖于实现的值。它的特殊设计适用于“标准”用途,并且仅在应用程序的生命周期内才有意义。默认算法并非旨在避免冲突。

    GetHashCode 方法并非设计为对每个实例都是唯一的。

    您的方法依赖于每列哈希的组成。哈希码必须满足某些要求,例如域中的分布。但是,不能保证组合保留这些属性和要求:添加的列越多,冲突可能就越多。

    另外,您正在调用value.GetHashCode(),这会阻碍装箱操作。正如 johey 所建议的,您应该使用 RuntimeHelpers.GetHashCode() 方法,因为它会在计算哈希之前将对象解释为值。

    .NET 数据结构设计用于在内部处理冲突,例如,IDictionary 使用哈希来选择存储桶,然后依次扫描存储桶。

    【讨论】:

      【解决方案3】:

      我想在这里写下我的解决方案。所说的一切都是真的,但并不完全正确。我想在这里收集话题。

      GetHashCode 总是为相同的对象提供相同的值。 GetHashCode 的值总是可能不属于不同的对象。

      所以首先比较GetHashCode的值以提高性能,如果GetHashCode的值相同,则进行下一步比较对象。

      我创建了一个 IEqualityComparer。

      private class CustomEqualityComparer<T> : IEqualityComparer<T>
          {
      
              private readonly List<string> _columns;
              private readonly bool _enableHashCode;
              private readonly ConcurrentDictionary<string, Func<T, object>> _cache;
              public CustomEqualityComparer(List<string> columns, ConcurrentDictionary<string, Func<T, object>> cache, bool enableHashCode = false)
              {
                  _columns = columns;
                  _enableHashCode = enableHashCode;
                  _cache = cache;
              }
      
              public bool Equals(T x, T y)
              {
                  for (var i = 0; i < _columns.Count; i++)
                  {
                      object value1 = GetValue(x, _columns[i], _cache);
                      object value2 = GetValue(y, _columns[i], _cache);
                      if (!value1.Equals(value2)) return false;
                  }
      
                  return true;
              }
      
              public int GetHashCode(T obj)
              {
                  return _enableHashCode ? GetHashCode(obj, _columns, _cache) : 0;
              }
      
              private object GetValue(object item, string propertyName, ConcurrentDictionary<string, Func<T, object>> cache)
              {
                  if (!cache.TryGetValue(propertyName, out Func<T, object> propertyResolver))
                  {
                      ParameterExpression arg = Expression.Parameter(item.GetType(), "x");
                      Expression expr = Expression.Property(arg, propertyName);
                      UnaryExpression unaryExpression = Expression.Convert(expr, typeof(object));
                      propertyResolver = Expression.Lambda<Func<T, object>>(unaryExpression, arg).Compile();
                      cache.TryAdd(propertyName, propertyResolver);
                  }
      
                  return propertyResolver((T)item);
              }
      
              private int GetHashCode(T obj, List<string> columns, ConcurrentDictionary<string, Func<T, object>> cache)
              {
                  unchecked
                  {
                      var hashCode = 17;
      
                      for (var i = 0; i < columns.Count; i++)
                      {
                          object value = GetValue(obj, columns[i], cache);
                          var tempHashCode = value == null ? 0 : value.GetHashCode();
                          hashCode = hashCode * 23 + tempHashCode;
                      }
      
                      return hashCode;
                  }
              }
          }
      

      【讨论】:

        猜你喜欢
        • 2016-04-10
        • 2022-11-29
        • 2011-05-20
        • 2014-12-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多