views:

358

answers:

1

Is there a default IEqualityComparer implementation that uses ReferenceEquals?

EqualityComparer<T>.Default uses ObjectComparer, which uses object.Equals(). In my case, the objects already implement IEquatable, which I need to ignore and compare by object's reference only.

Thanks!

+5  A: 

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 ObjectReferenceEqualityComparerer<T> : EqualityComparer<T>
    where T : class
{
    private static IEqualityComparer<T> _defaultComparer;

    public new static IEqualityComparer<T> Default
    {
        get { return _defaultComparer ?? (_defaultComparer = new ObjectReferenceEqualityComparerer<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
}
Yurik
The only thing I didn't like about this is the `Default` property violates the purity assumption of a property getter. Since the CLR won't run the static initializer for the class until some member of the class is referenced, the inline initialization I added has the same effective lazy initialization effect as the property did but doesn't violate the purity constraint. I also sealed the type.
280Z28
Last but not least, I derived from EqualityComparer<T> to pick up the implementation of IEqualityComparer (non-generic). On a side note, this exact type is an `internal` class in the System.Xaml assembly from .NET 4 (in the System.Xaml.Schema namespace).
280Z28
I didn't even think of the null case - thanks!As for Default - EqualityComparer.Default (default comparerer used internally) has similar structure. Guess MS is not following its own guidelines :)
Yurik