【问题标题】:generic reference equality comparer does not work for ValueTuple通用引用相等比较器不适用于 ValueTuple
【发布时间】:2017-10-06 03:20:16
【问题描述】:

我编写了一个通用的相等比较器,无论参数类型的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(在这种情况下是一对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 的输入,因此将使用默认比较器。这意味着,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) 上使用与在 Item1s 和 Item2s 和 &amp;&amp;ing 上都使用 ReferenceEquals 不一样结果?和GetHashCode类似?

【问题讨论】:

    标签: c# generics iequalitycomparer valuetuple


    【解决方案1】:

    ReferenceEquals 和 object.Equals 不一样

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

    在两个(对象,对象)上使用 ReferenceEquals 与在 Item1s 和 Item2s 上使用 ReferenceEquals 并 &&ing 结果不一样吗?

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

    和GetHashCode类似吗?

    类似,第一个版本使用 ValueTuple 实现,它根据元组中项目的值计算散列,而第二个版本完全根据对对象本身的引用计算散列,因此,当您对两个不同的对象有两个不同的引用,但这些对象但这两个对象在内部具有等效值时,第一个认为它们相等,第二个认为它们不相等。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-05
      • 1970-01-01
      • 1970-01-01
      • 2016-08-05
      • 1970-01-01
      • 1970-01-01
      • 2022-01-17
      相关资源
      最近更新 更多