C# IEqualityComparer<;T>;使用ReferenceEquals的

C# IEqualityComparer<;T>;使用ReferenceEquals的,c#,.net,iequalitycomparer,referenceequals,C#,.net,Iequalitycomparer,Referenceequals,是否有默认的IEqualityComparer实现使用ReferenceEquals EqualityComparer.Default使用ObjectComparer,它使用object.Equals()。在我的例子中,对象已经实现了IEquatable,我只需要忽略它并通过对象的引用进行比较。如果没有默认实现,这是我自己的: 由280Z28编辑:使用的基本原理,你们中的许多人可能以前都没有见过。:)此方法具有两种效果,使其成为此实现的正确调用: 当对象为空时,它返回0。由于ReferenceE

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


EqualityComparer.Default
使用ObjectComparer,它使用
object.Equals()
。在我的例子中,对象已经实现了
IEquatable
,我只需要忽略它并通过对象的引用进行比较。

如果没有默认实现,这是我自己的:

由280Z28编辑:使用的基本原理,你们中的许多人可能以前都没有见过。:)此方法具有两种效果,使其成为此实现的正确调用:

  • 当对象为空时,它返回0。由于
    ReferenceEquals
    适用于空参数,因此比较器的GetHashCode()实现也应如此
  • 它称之为非虚拟
    ReferenceEquals
    特别忽略对
    Equals
    的任何重写,因此GetHashCode()的实现应该使用与ReferenceEquals效果匹配的特殊方法,这正是RuntimeHelpers.GetHashCode的用途
  • [完二八〇〇年二月二十八日]

    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
    }
    
    使用系统;
    使用System.Collections.Generic;
    使用System.Runtime.CompilerServices;
    /// 
    ///仅使用对象引用的通用对象比较器,
    ///忽略任何或覆盖。
    /// 
    公共类对象引用EqualityComparer:EqualityComparer
    T:在哪里上课
    {
    专用静态IEqualityComparer\u defaultComparer;
    公共新静态IEqualityComparer默认值
    {
    获取{return\u defaultComparer??(\u defaultComparer=new ObjectReferenceEqualityComparer());}
    }
    #地区资格比较成员
    公共覆盖布尔等于(TX,TY)
    {
    返回引用等于(x,y);
    }
    公共覆盖int GetHashCode(T obj)
    {
    返回RuntimeHelpers.GetHashCode(obj);
    }
    #端区
    }
    
    我认为是时候将以前的answers实现更新到.Net4.0+了,由于
    IEqualityComparer
    界面上的差异,这里不再需要泛型:

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

    为那些不熟悉…概念的人澄清

    class-MyClass
    {
    ISet setOfMyClass=新哈希集(ReferenceEqualityComparer.Default);
    }
    

    …以上代码编译;请注意,它不是说HashSet,而是说HashSet,这是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);
    }
    
    公共密封类引用EqualityComparer:IEqualityComparer,IEqualityComparer
    {
    public static ReferenceEqualityComparer默认值{get;}=new ReferenceEqualityComparer();
    公共新bool Equals(对象x,对象y)=>ReferenceEquals(x,y);
    public int GetHashCode(objectobj)=>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);
    }
    
    公共密封类引用EqualityComparer:IEqualityComparer其中T:class
    {
    公共静态IEqualityComparer默认值{get;}=new ReferenceEqualityComparer();
    公共布尔等于(tx,ty)=>ReferenceEquals(x,y);
    public int GetHashCode(T obj)=>RuntimeHelpers.GetHashCode(obj);
    }
    
    Microsoft在
    系统.数据.实体.基础设施中提供
    对象引用平等比较程序

    只需使用
    ObjectReferenceEqualityComparer.Default
    作为比较器。

    在.NET 5.0中,您现在有了

    我唯一不喜欢的是
    Default
    属性违反了属性getter的纯度假设。由于CLR在引用类的某个成员之前不会运行该类的静态初始值设定项,因此我添加的内联初始化与属性具有相同的有效延迟初始化效果,但不会违反纯度约束。最后但并非最不重要的一点是,我从EqualityComparer派生来获取IEqualityComparer(非泛型)的实现。另一方面,这个确切的类型是.NET 4中System.Xaml程序集(在System.Xaml.Schema命名空间中)中的
    内部
    类。我认为
    默认
    标识符令人困惑。为什么无缘无故隐藏继承的成员。我会将
    Default
    属性重命名为
    Instance
    (或者完全忽略它,实例构造函数是
    public
    )。从
    EqualityComparer
    继承不是一个好主意。静态成员“继承”确实令人困惑;所以像这样重用
    Default
    不是一个好主意。此外,虚拟方法比普通方法慢;既然这可能是一种在紧循环中使用的类型,为什么要增加不必要的开销呢?最后,实现
    IEqualityComparer
    对于您已经拥有的东西来说是微不足道的,那么为什么不直接实现并避免依赖关系呢?@eamonnerbanne这些方法无论如何都是虚拟调用,因为类型几乎完全是通过IEqualityComparer接口使用的。一旦方法在vtable中,无论在何处实现,调用开销都是相同的。Quote:“
    由于IEqualityComparer接口上的逆变
    ”不,
    IEqualityComparer
    t
    @TysonWilliams中是协变的,我没有弄错。请参阅。这会给出警告CS0108:“ReferenceEqualityComparer.Equals(对象,对象)”隐藏继承的成员“object.Equals(对象,对象)”。如果打算隐藏,请使用新关键字。显式实现接口,它将完全解决隐藏问题。我想没有人会直接使用
    ReferenceEqualityComparer.Default.Equals(a,b)
    而不是
    ReferenceEquals(a,b)
    。如果传递到一个需要
    IEqualityComparer
    -的地方,一切都可以。不,因为它使用了可能被覆盖的
    对象。等于
    对象。GetHashCode
    。实际上不应该使用
    new
    关键字。正如警告所说,
    “如果打算隐藏,请使用新关键字。”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);
    }