GetHashCode() 经常重写冲突方式
GetHashCode() override coliding way to often
我正在使用 unity,而 unity 中没有元组,所以我创建了自己的元组 class 来工作,因为我的字典需要它。
Dictionary <Tuple<int,int>, Tile>
我创建的 Tile class 与解决此问题无关(至少我认为它无济于事)。
但问题是我在我的元组中同时使用负整数和正整数,当我将当前的 GetHashCode()
与 Tuples
一起使用时,有时我会得到相同的 HashCode,因为例如 Tuple<-10, 8>
和 Tuple<-9,-10>
当我 return 哈希码时都给出 -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);
}
此外,不要忘记考虑 obj1
和 obj2
都是 null
的情况。
如果您要实现自己的 Tuple
,您可能会考虑从 Reference Source 存储库中窃取 Microsoft 的,或者至少将其用作您自己的基础。
I'm using unity, and unity does not have a tuple in it
如果您有 Unity 2017 及更高版本,它支持 Tuple。
转到编辑 --> 项目设置 --> 播放器 --> 其他设置 --> Configuration --> Scripting Runtime Version --> .NET 4.x Equivalent.
重新加载或重新启动 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
实现中很有用。它会自动比较所有 public 属性(所以如果你添加一个新的 public 属性 你不需要改变任何东西 except 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();
}
}
}
}
(*) 我在网上的某个地方找到了它,可惜我不记得在哪里,Google 在这里让我失望了。
我正在使用 unity,而 unity 中没有元组,所以我创建了自己的元组 class 来工作,因为我的字典需要它。
Dictionary <Tuple<int,int>, Tile>
我创建的 Tile class 与解决此问题无关(至少我认为它无济于事)。
但问题是我在我的元组中同时使用负整数和正整数,当我将当前的 GetHashCode()
与 Tuples
一起使用时,有时我会得到相同的 HashCode,因为例如 Tuple<-10, 8>
和 Tuple<-9,-10>
当我 return 哈希码时都给出 -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);
}
此外,不要忘记考虑 obj1
和 obj2
都是 null
的情况。
如果您要实现自己的 Tuple
,您可能会考虑从 Reference Source 存储库中窃取 Microsoft 的,或者至少将其用作您自己的基础。
I'm using unity, and unity does not have a tuple in it
如果您有 Unity 2017 及更高版本,它支持 Tuple。
转到编辑 --> 项目设置 --> 播放器 --> 其他设置 --> Configuration --> Scripting Runtime Version --> .NET 4.x Equivalent.
重新加载或重新启动 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
实现中很有用。它会自动比较所有 public 属性(所以如果你添加一个新的 public 属性 你不需要改变任何东西 except 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();
}
}
}
}
(*) 我在网上的某个地方找到了它,可惜我不记得在哪里,Google 在这里让我失望了。