IEqualityComparer that uses ReferenceEquals

后端 未结 5 1971
野趣味
野趣味 2020-11-28 09:33

Is there a default IEqualityComparer implementation that uses ReferenceEquals?

EqualityComparer.Default uses

相关标签:
5条回答
  • 2020-11-28 10:02

    Just in case there is no default implementation, this is my own:

    Edit by 280Z28: Rationale for using RuntimeHelpers.GetHashCode(object), which many of you probably haven't seen before. :) This method has two effects that make it the correct call for this implementation:

    1. It returns 0 when the object is null. Since ReferenceEquals works for null parameters, so should the comparer's implementation of GetHashCode().
    2. It calls Object.GetHashCode() non-virtually. ReferenceEquals specifically ignores any overrides of Equals, so the implementation of GetHashCode() should use a special method that matches the effect of ReferenceEquals, which is exactly what RuntimeHelpers.GetHashCode is for.

    [end 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
    }
    
    0 讨论(0)
  • 2020-11-28 10:03

    In .NET 5.0 you now have System.Collections.Generic.ReferenceEqualityComparer

    0 讨论(0)
  • 2020-11-28 10:08

    Here's a simple implementation for C# 6 and later:

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

    Or a generic version:

    public sealed class ReferenceEqualityComparer<T> : IEqualityComparer<T>
    {
        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);
    }
    
    0 讨论(0)
  • 2020-11-28 10:17

    I thought it was time to update the previous answers implementation to .Net4.0+ where it simplifies by becoming non-generic thanks to contravariance on the IEqualityComparer<in T> interface:

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

    Now there only needs to exist one instance for all your reference-equality checking instead of one for each type T as was the case before.

    Also you save typing by not having to specify T every time you want to use this!


    To clarify for those who are not familiar with the concepts of Covariance and Contravariance...

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

    ...will work just fine. This is not limited to e.g. HashSet<object> or similar (in .Net4.0).


    Also for anyone wondering why x == y is reference equality, it is because the ==operator is a static method, which means it is resolved at compile-time, and at compile-time x and y are of type object so here it resolves to the ==operator of object - which is the real reference equality method. (In fact the Object.ReferenceEquals(object, object) method is simply a redirect to the object equals operator.)

    0 讨论(0)
  • 2020-11-28 10:28

    Microsoft provide ObjectReferenceEqualityComparer in System.Data.Entity.Infrastructure. Just use ObjectReferenceEqualityComparer.Default as comparer.

    0 讨论(0)
提交回复
热议问题