【发布时间】:2017-10-06 03:20:16
【问题描述】:
我编写了一个通用的相等比较器,无论参数类型的GetHashCode 和Equals 方法看起来如何,它都应该始终按引用进行比较:
public class ReferenceEqualityComparer<T> : IEqualityComparer<T>
{
public static ReferenceEqualityComparer<T> Inst = new ReferenceEqualityComparer<T>();
private ReferenceEqualityComparer() { }
public bool Equals(T x, T y) { return ReferenceEquals(x, y); }
public int GetHashCode(T obj) { return RuntimeHelpers.GetHashCode(obj); }
}
我像这样扔了一个ValueTuple(在这种情况下是一对objects):
var objectPairComparer = ReferenceEqualityComparer<(object,object)>.Inst;
但是这个比较器的行为不像预期的那样,所以我想我做错了什么。要查看问题所在,首先考虑以下情况:
object a = new object();
object b = new object();
object c = a;
object d = b;
HashSet<(object, object)> set = new HashSet<(object, object)>();
Console.WriteLine("set.Add((a, b)) = " + set.Add((a, b))); // returns true
Console.WriteLine("set.Contains((c, d)) = " + set.Contains((c, d))); // returns true
Console.WriteLine("set.Add((c, d)) = " + set.Add((c, d))); // returns false
由于没有比较器作为HashSet 的输入,因此将使用默认比较器。这意味着,Item1 和 Item2 都将使用引用相等和默认哈希码(地址或其他内容)。输出符合我的预期。
但如果我改为使用比较器
HashSet<(object,object)> set = new HashSet<(object,object)>(objectPairComparer);
然后输出改变:
Console.WriteLine("set.Add((a, b)) = " + set.Add((a, b))); // returns true like before
Console.WriteLine("set.Contains((c, d)) = " + set.Contains((c, d))); // returns FALSE
Console.WriteLine("set.Add((c, d)) = " + set.Add((c, d))); // returns TRUE
但它们的行为方式应该相同!他们为什么不呢? ReferenceEquals 与 object.Equals 不一样,ReferenceEquals 在两个 (object,object) 上使用与在 Item1s 和 Item2s 和 &&ing 上都使用 ReferenceEquals 不一样结果?和GetHashCode类似?
【问题讨论】:
标签: c# generics iequalitycomparer valuetuple