通用引用相等比较器不适用于ValueTuple

时间:2017-10-05 17:26:35

标签: c# generics iequalitycomparer valuetuple

我编写了一个通用的相等比较器,无论参数类型的GetHashCodeEquals方法如何,都应该总是通过引用进行比较:

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(在这种情况下是一对object s),如下所示:

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的输入,因此将使用默认比较器。这意味着,Item1Item2都将使用引用相等和默认哈希码(地址或其他内容)。输出是我所期望的。

但如果我改为使用比较器

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

但他们应该以同样的方式行事!他们为什么不这样做?不是ReferenceEqualsobject.Equals相同,并且ReferenceEquals(object,object)上使用的ReferenceEquals与使用Item1上的Item2相同&& s和GetHashCode s以及Prelude> (i, j) = (3, 4) Prelude> (i, j) = (j, i) Prelude> i 结果?和4类似吗?

1 个答案:

答案 0 :(得分:1)

  

ReferenceEquals与object.Equals

不同

不,不是。 object.Equals将在第一个操作数上使用虚拟分派,为对象的实际运行时类型找到Equals的实现,并使用该类型定义所要执行的任何操作。在ValueTuple的情况下,它将比较两个元组的实际值。 ReferenceEquals只是比较引用并告诉您它们是否相等。在这种特殊情况下,您有两个不同的引用,即使每个引用引用的值相同。

  

不是在两个(对象,对象)上使用的ReferenceEquals与在Item1s和Item2s上使用ReferenceEquals以及&amp;&amp; ing结果相同吗?

不,不是。它只是 会告诉您传入的两个对象是否都是同一个对象的相同引用。他们不会检查这些对象的实际值。在这种情况下,您有两个不同的引用,因此它们不相等。

  

和GetHashCode类似吗?

这是类似的,因为第一个版本使用ValueTuple实现,它根据元组中项的值计算哈希值,而第二个版本完全根据对象的引用计算哈希值本身,所以当你对两个不同的对象有两个不同的引用,但是那些对象但是那两个对象在内部具有等价值的地方,第一个认为它们相等,第二个认为它们是不相等的。