簡體   English   中英

GetHashCode為不同的對象返回相同的值。 是否有通過特定屬性標識對象的方法?

[英]GetHashCode returns the same value for different objects. Is there any method to identify object by particular properties?

我正在嘗試創建一個hashcode方法。 我有如下代碼:

    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步驟:

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

k1和k2為何值相同? 因為默認的.net gethashcode方法提供了兩個不同的值。 我想創建一個可以獲取列列表的哈希碼方法。 我想通過特定屬性創建一個哈希碼。 我正在嘗試通過特定屬性為對象獲取唯一值。

如果GetHashCode不保證唯一值,如何通過特定屬性識別對象?

我懷疑問題是由您的GetHashCode<T>方法中的value.GetHashCode()引起的。 該值變量在那里是一個對象,我認為GetHashCode()不會返回您期望的結果。 嘗試調試以找出正在發生的情況。

您可能想嘗試保留代碼,但請使用RuntimeHelpers.GetHashCode() (來自命名空間System.Runtime.CompilerServices )來代替Object.GetHashCode() )。

此處的完整參考資料: https : //docs.microsoft.com/zh-cn/dotnet/api/system.runtime.compilerservices.runtimehelpers.gethashcode?redirectedfrom=MSDN&view=netframework-4.7.2#System_Runtime_CompilerServices_RuntimeHelpers_GetHashCode_System_Object_

祝好運!

GetHashCode返回與實現相關的值。 其特殊的設計適合“標准”使用,並且僅在應用程序的生命周期內才有意義。 默認算法並非旨在避免沖突。

GetHashCode方法並非每個實例都唯一。

您的方法依賴於每列哈希的組成。 哈希碼必須滿足某些要求,例如域中的分布。 但是,不能保證該組合物保留這些屬性和要求:添加的列越多,沖突可能就越“陌生”。

另外,您正在調用value.GetHashCode() ,這會阻止裝箱操作。 如johey所建議,您應該使用RuntimeHelpers.GetHashCode()方法,因為它在計算哈希值之前會將對象解釋為值。

.NET數據結構旨在內部處理沖突,例如, IDictionary使用哈希值選擇存儲桶,然后依次掃描該存儲桶。

我想在這里寫我的解決方案。 所有的說法都是正確的,但並非完全正確。 我想在這里收集話題。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM