Is there any kind of "ReferenceComparer" in .NET?

2.1k views Asked by At

There are several places in BCL where one can make use of IEqualityComparer. Like Enumerable.Contains or Dictionary Constructor. I can provide my comparer if I'm not happy with the default one.

Sometimes I want to know whether the collection contains that very object that I have reference to. Not the one that is considered "equal" in any other meaning.
The question is: whether there exists standard equality comparer in the BCL that relies only on ReferenceEquals method?

The one that I wrote myself is this:

class ReferenceComparer<T> : IEqualityComparer<T> where T : class
{
    private static ReferenceComparer<T> m_instance;

    public static ReferenceComparer<T> Instance
    {
        get
        {
            return m_instance ?? (m_instance = new ReferenceComparer<T>());
        }
    }

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

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

I didn't test it thoroughly nor considered lots of scenarios, but it seems to make Enumerable.Contains and Dictionary pretty happy.

2

There are 2 answers

4
Ani On BEST ANSWER

As far as I know, the BCL doesn't expose any public types that implement IEqualityComparer<T> with reference-equality as of .NET 4.0 .

However, there do appear to be a bunch of internal types that do this, such as:

  • System.Dynamic.Utils.ReferenceEqualityComparer<T> (in System.Core)
  • System.Xaml.Schema.ReferenceEqualityComparer<T> (in System.Xaml).

I took a look at the implementations of these two types with reflector, and you'll be happy to know that both of them appear to be implemented in a way that is virtually identical to yours, except that they don't use lazy-initialization for the static instance (they create it in the static constructor for the type).

The only possible 'issue' I can think of with your implementation is that the lazy-initialization is not thread-safe, but since instances are 'cheap' and aren't holding onto any state, that shouldn't create any bugs or major performance problems. If you want to enforce the singleton-pattern though, you'll have to do it properly.

0
Samuel S. On

I end up using this solution also as I could not find any workaround.

To fix the non thread safe implementation, you could easily use a static initiailizer.

public static ReferenceComparer<T> Instance => new ReferenceComparer<T>();

(sorry for the answer instead of a comment to up-voted thread, I have a new account with no comment rights, yet).