簡體   English   中英

GetHashCode()經常覆蓋coliding方式

[英]GetHashCode() override coliding way to often

我正在使用統一,並且團結中沒有元組,所以我創建了自己的元組類來工作,因為我需要它用於我的字典。

Dictionary <Tuple<int,int>, Tile>

我創建的瓷磚類並沒有真正解決這個問題(至少我認為它不會有幫助)。

但問題是我在元組中使用負整數和正整數,當我使用當前的GetHashCode()Tuples ,有時候我會得到相同的HashCode,例如Tuple<-10, 8>Tuple<-9,-10>當我返回哈希碼時Tuple<-9,-10>都給出-172。

是否有任何好的GetHashCode不會讓我發生沖突? 說實話,我只使用運算符== ,因為我需要檢查兩個元組內部是否有相同的整數,如果我可以得到一個運算符==只有當兩個整數相同且相同時才會發生碰撞它會解決我的問題。

其他一些小問題,我無法理解Equals覆蓋,因為它正在工作,但我不知道它有多好用,因為我改變了每一件事,直到它工作。

public class Tuple<T1, T2>
{
    public T1 First { get; private set; }
    public T2 Second { get; private set; }

    public Tuple(T1 _First, T2 _Second)
    {
        First = _First;
        Second = _Second;
    }
    public override int GetHashCode()
    {
        int hash = 0;

        hash = First.GetHashCode() * 17 + Second.GetHashCode() + First.GetHashCode();

        return hash;
    }
    public static bool operator==(Tuple<T1, T2> obj1, Tuple<T1, T2> obj2)
    {
        if (ReferenceEquals(null, obj2))
            return false;
        return (obj1.GetHashCode() == obj2.GetHashCode());
    }
    public static bool operator!=(Tuple<T1, T2> obj1, Tuple<T1, T2> obj2)
    {
        if (ReferenceEquals(null, obj2))
            return true;
        return !(obj1.GetHashCode() == obj2.GetHashCode());
    }
    public bool Equals(Tuple<T1, T2> other)
    {
        if (other == null)
            return false;

        if (GetHashCode() == other.GetHashCode())
            return true;
        else
            return false;

    }
    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj))
        {
            return false;
        }
        if (ReferenceEquals(this, obj))
        {
            return true;
        }

        Tuple<T1, T2> other = obj as Tuple<T1, T2>;

        return obj.GetType() == GetType() && Equals(other);
    }
}
public static class Tuple
{
    public static Tuple<T1, T2> New<T1, T2>(T1 first, T2 second)
    {
        var tuple = new Tuple<T1, T2>(first, second);
        return tuple;
    }
}

GetHashCode()不應該是無沖突的。 您應該使用它來確定兩個東西是否可能是相同的對象,然后您必須實際進行徹底檢查以確定它們是否相同。

例如,您的==方法應該更像這樣寫:

public static bool operator==(Tuple<T1, T2> obj1, Tuple<T1, T2> obj2)
{
    if (ReferenceEquals(null, obj2))
        return false;

    if (obj1.GetHashCode() != obj2.GetHashCode())
    {
        return false;
    }
    return DefaultComparer<T1>.Equals(obj1.First, obj2.First) && DefaultComparer<T2>.Equals(obj1.Second, obj2.Second);
}

另外,不要忘記考慮obj1obj2都為null

如果您正在實現自己的Tuple ,您可能會考慮從參考源存儲庫竊取Microsoft,或至少將其用作您自己的基礎。

我正在使用團結,團結並沒有一個元組

如果你有Unity 2017及以上版本,它支持元組。

轉到編輯 - > 項目設置 - >播放器 - > 其他設置 - > 配置 - > 腳本運行時版本 - > .NET 4.x等效

重新加載或重新啟動Visual Studio,您應該能夠使用Tuple 如果您不使用Unity 2017及更高版本且也不想更新,請參閱John的答案

這就是resharper自動為您生成的內容。 只需注意他們如何處理GetHashCode()和Equals。

private class Tuple<T1,T2> : IEquatable<Tuple<T1, T2>>
{
    public T1 First {get;}
    public T2 Second {get;}

    public Tuple(T1 first, T2 second)
    {
        First = first;
        Second = second;
    }

    public bool Equals(Tuple<T1, T2> other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return EqualityComparer<T1>.Default.Equals(First, other.First) && EqualityComparer<T2>.Default.Equals(Second, other.Second);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != this.GetType()) return false;
        return Equals((Tuple<T1, T2>) obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return (EqualityComparer<T1>.Default.GetHashCode(First) * 397) ^ EqualityComparer<T2>.Default.GetHashCode(Second);
        }
    }

    public static bool operator ==(Tuple<T1, T2> left, Tuple<T1, T2> right)
    {
        return Equals(left, right);
    }

    public static bool operator !=(Tuple<T1, T2> left, Tuple<T1, T2> right)
    {
        return !Equals(left, right);
    }
}

我發現PropertyCompare (*)在自動生成Equals實現時很有用。 它會自動比較所有公共屬性(因此,如果添加新的公共屬性, 除了 GetHashCode 之外,您不需要更改任何內容(甚至在技術上是可選的)。

它使用Cache具有合理的性能 - 它需要一次性命中(每種類型)來為比較生成適當的表達式。

using System;
using System.Linq.Expressions;

namespace YourApp
{
    public class Tuple<T1, T2>
    {
        public T1 First { get; private set; }
        public T2 Second { get; private set; }

        public Tuple(T1 _First, T2 _Second)
        {
            First = _First;
            Second = _Second;
        }
        public override int GetHashCode()
        {
            var hash = 0;

            // Implement this however you like
            hash = First.GetHashCode() * 17 + Second.GetHashCode() + First.GetHashCode();

            return hash;
        }
        public static bool operator ==(Tuple<T1, T2> x, Tuple<T1, T2> y)
        {
            return PropertyCompare.Equal(x, y);
        }
        public static bool operator !=(Tuple<T1, T2> x, Tuple<T1, T2> y)
        {
            return !PropertyCompare.Equal(x, y);
        }
        public bool Equals(Tuple<T1, T2> other)
        {
            return PropertyCompare.Equal(this, other);

        }
        public override bool Equals(object obj)
        {
            return PropertyCompare.Equal(this, obj);
        }
    }
    public static class Tuple
    {
        public static Tuple<T1, T2> New<T1, T2>(T1 first, T2 second)
        {
            var tuple = new Tuple<T1, T2>(first, second);
            return tuple;
        }
    }

    public class Program
    {
        public static void Main()
        {
            var bob1 = Tuple.New("a", 1);
            var bob2 = Tuple.New("a", 1);

            Console.WriteLine(bob1 == bob2);
            Console.ReadLine();
        }
    }

    public static class PropertyCompare
    {
        public static bool Equal<T>(T x, object y) where T : class
        {
            return Cache<T>.Compare(x, y as T);
        }

        public static bool Equal<T>(T x, T y)
        {
            if (x == null)
            {
                return y == null;
            }

            if (y == null)
            {
                return false;
            }

            return Cache<T>.Compare(x, y);
        }

        private static class Cache<T>
        {
            internal static readonly Func<T, T, bool> Compare;
            static Cache()
            {
                var props = typeof(T).GetProperties();
                if (props.Length == 0)
                {
                    Compare = delegate { return true; };
                    return;
                }
                var x = Expression.Parameter(typeof(T), "x");
                var y = Expression.Parameter(typeof(T), "y");

                Expression body = null;
                for (var i = 0; i < props.Length; i++)
                {
                    var propEqual = Expression.Equal(
                        Expression.Property(x, props[i]),
                        Expression.Property(y, props[i]));
                    if (body == null)
                    {
                        body = propEqual;
                    }
                    else
                    {
                        body = Expression.AndAlso(body, propEqual);
                    }
                }
                Compare = Expression.Lambda<Func<T, T, bool>>(body, x, y)
                              .Compile();
            }
        }
    }
}

(*)我在網上找到了它,唉我記不起來了,谷歌在這里讓我失望了。

暫無
暫無

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

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