有默认的吗 IEqualityComparer<T> 使用的实现 ReferenceEquals?

EqualityComparer<T>.Default 使用 ObjectComparer,它使用 object.Equals(). 。就我而言,对象已经实现了 IEquatable<T>, ,我需要忽略它并仅通过对象的引用进行比较。

有帮助吗?

解决方案

以防万一没有默认实现,这是我自己的:

280Z28 编辑:使用理由 RuntimeHelpers.GetHashCode(object), ,你们中的许多人可能以前没有见过。:) 这个方法有两个效果,使其成为 正确的 呼吁实施:

  1. 当对象为空时,它返回 0。自从 ReferenceEquals 适用于空参数,比较器的 GetHashCode() 实现也应该如此。
  2. 它调用 Object.GetHashCode() 非虚拟。 ReferenceEquals 特别忽略任何覆盖 Equals, ,所以 GetHashCode() 的实现应该使用与 ReferenceEquals 效果相匹配的特殊方法,这正是 RuntimeHelpers.GetHashCode 的用途。

[280Z28结束]

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

/// <summary>
/// A generic object comparerer that would only use object's reference, 
/// ignoring any <see cref="IEquatable{T}"/> or <see cref="object.Equals(object)"/>  overrides.
/// </summary>
public class ObjectReferenceEqualityComparer<T> : EqualityComparer<T>
    where T : class
{
    private static IEqualityComparer<T> _defaultComparer;

    public new static IEqualityComparer<T> Default
    {
        get { return _defaultComparer ?? (_defaultComparer = new ObjectReferenceEqualityComparer<T>()); }
    }

    #region IEqualityComparer<T> Members

    public override bool Equals(T x, T y)
    {
        return ReferenceEquals(x, y);
    }

    public override int GetHashCode(T obj)
    {
        return RuntimeHelpers.GetHashCode(obj);
    }

    #endregion
}

其他提示

我认为是时候将之前的答案实现更新到 .Net4.0+ 了,由于 IEqualityComparer<in T> 界面:

using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

public sealed class ReferenceEqualityComparer
    : IEqualityComparer, IEqualityComparer<object>
{
    public static readonly ReferenceEqualityComparer Default
        = new ReferenceEqualityComparer(); // JIT-lazy is sufficiently lazy imo.

    private ReferenceEqualityComparer() { } // <-- A matter of opinion / style.

    public bool Equals(object x, object y)
    {
        return x == y; // This is reference equality! (See explanation below.)
    }

    public int GetHashCode(object obj)
    {
        return RuntimeHelpers.GetHashCode(obj);
    }
}

现在,所有引用相等性检查只需要存在一个实例,而不是每种类型都有一个实例 T 就像之前的情况一样。

您还可以通过无需指定来节省打字时间 T 每次你想用这个的时候!


为那些不熟悉这些概念的人澄清 协变和逆变...

class MyClass
{
    ISet<MyClass> setOfMyClass = new HashSet<MyClass>(ReferenceEqualityComparer.Default);
}

...会工作得很好。这是 不是 仅限于例如 HashSet<object> 或类似的(在.Net4.0中)。


也适合任何想知道为什么的人 x == y 是引用相等,这是因为 ==运算符是静态方法,这意味着它在编译时解析,并且在编译时 x 和 y 的类型 object 所以这里解决了 ==的运算符 object - 哪一个是 真实的 参考相等法。(事实上 Object.ReferenceEquals(object, object) 方法只是重定向到对象等于运算符。)

下面是C#6的简单实现。

public sealed class ReferenceEqualityComparer : IEqualityComparer, IEqualityComparer<object>
{
    public static ReferenceEqualityComparer Default { get; } = new ReferenceEqualityComparer();

    public new bool Equals(object x, object y) => ReferenceEquals(x, y);
    public int GetHashCode(object obj) => RuntimeHelpers.GetHashCode(obj);
}

修改(您不必阅读这一点,除非你有兴趣在下面的评论)

@AnorZaken倾注了段落这里new改性剂的三个字母。让我们来总结一下。

在单个定义的实例Equals(object,object)方法实现用于这种类型,Equals和其通用对应IEqualityComparer两个声明的接口的IEqualityComparer<object>方法。签名是相同的,所以该定义满足这两个接口。

在实例方法ReferenceEqualityComparer.Equals(object,object)隐藏静态 object.Equals(object,object)方法。

没有new编译器发出警告此。什么,这实际上意味着?

这意味着,如果你要调用静态object.Equals方法,你不能把它的ReferenceEqualityComparer实例的。这是一个大问题?

没有。事实上,它的预期的行为。这意味着,如果你要调用object.Equals(a,b)你无法通过代码做到这一点,如ReferenceEqualityComparer.Default.Equals(a,b)。该代码显然是请求的引用的平等 - 没有人会合理地期望它执行默认/值相等。你为什么不只是反正代码更明确object.Equals(a,b)?所以使用new提供合理的和所期望的行为,并允许编译没有警告。

如何你还能抑制警告?如果使用#pragma warning disable 108 / #pragma warning restore 108那么结果是一样的使用new,除非你已经添加了一堆更多的噪音对你的代码。 new足够并且更清楚地解释的意图给他人。

另外,您可以使用显式实现两个接口Equals方法,但随后如果使用ReferenceEqualityComparer.Default.Equals(a,b)你就不必参考平等可言。

在现实中,隐藏静态方法与实例方法是很少会成为问题,因为静态方法是从一个类型说明符,不是一个实例说明符解除引用。也就是说,你用Foo.StaticMethod()new Foo().StaticMethod()。从实例调用静态方法是不必要充其量和误导/在最坏的情况不正确。

此外,对于平等comparers,你很少直接使用他们的具体类型。相反,你使用他们的API,例如集合。

因此,虽然这是一个有趣,有时令人困惑的讨论,这是相当徒劳的。

微软提供ObjectReferenceEqualityComparerSystem.Data.Entity.Infrastructure。 只要使用ObjectReferenceEqualityComparer.Default作为比较器。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top