64

是否有使用的默认IEqualityComparer<T>实现ReferenceEquals

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

4

5 回答 5

61

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

由 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
}
于 2009-12-11T19:09:54.180 回答
20

我认为是时候将以前的答案实现更新为 .Net4.0+,由于接口上的逆变,不再需要泛型IEqualityComparer<in T>

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

public sealed class ReferenceEqualityComparer
    : IEqualityComparer, IEqualityComparer<object>
{
    private ReferenceEqualityComparer() { }

    public static readonly ReferenceEqualityComparer Default
        = new ReferenceEqualityComparer();

    public /*new*/ 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每次都指定要使用它,并且还避免了不必要的通用运行时类型的污染。


至于为什么x == y是引用相等,那是因为==操作符是一个静态方法,也就是说它是在编译时解析的,而在编译时xandy参数的类型是object.

事实上,这就是Object.ReferenceEquals(object, object)方法 代码的样子:

public static bool ReferenceEquals(object objA, object objB) {
    return objA == objB;
}

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

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

...上面的代码编译;请注意,它没有HashSet<object>.

于 2016-02-20T07:01:00.697 回答
10

这是 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);
}

或确保它仅可用于引用类型的通用版本:

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

    public bool Equals(T x, T y) => ReferenceEquals(x, y);
    public int GetHashCode(T obj) => RuntimeHelpers.GetHashCode(obj);
}
于 2016-12-15T16:56:29.633 回答
10

在 .NET 5.0 中,您现在拥有System.Collections.Generic.ReferenceEqualityComparer

于 2020-09-18T11:30:52.900 回答
0

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

于 2019-08-28T19:46:21.033 回答