Подтвердить что ты не робот

Есть ли какой-либо "ReferenceComparer" в .NET?

В BCL есть несколько мест, где можно использовать IEqualityComparer. Как Enumerable.Contains или конструктор словаря. Я могу предоставить свой компас, если меня не устраивает по умолчанию.

Иногда я хочу знать, содержит ли коллекция тот самый объект, на который я ссылаюсь. Не тот, который считается "равным" в любом другом значении.
Возникает вопрос: существует ли в BCL стандартный сопоставитель равенства, который опирается только на метод ReferenceEquals?

Тот, который я написал сам, таков:

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

Я не тестировал его полностью и не рассматривал множество сценариев, но, похоже, он очень рад. и Dictionary.

4b9b3361

Ответ 1

Насколько мне известно, BCL не раскрывает никаких публичных типов, которые реализуют IEqualityComparer<T> с помощью ссылки-равенства по сравнению с .NET 4.0.

Однако, похоже, для этого существует куча внутренних типов, таких как:

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

Я взглянул на реализации этих двух типов с отражателем, и вы будете рады узнать, что оба они реализованы таким образом, который практически идентичен вашим, за исключением того, что они не используют lazy-initialization для статического экземпляра (они создают его в статическом конструкторе для типа).

Единственная возможная проблема, которую я могу придумать с вашей реализацией, заключается в том, что ленивая инициализация не является потокобезопасной, но поскольку экземпляры являются "дешевыми" и не удерживаются в каком-либо состоянии, это не должно создавать никаких ошибок или серьезных проблем с производительностью. Если вы хотите применить синглтон-шаблон, вам нужно будет сделать это правильно.

Ответ 2

В конечном итоге я использую это решение, так как не могу найти обходного пути.

Чтобы исправить небезопасную реализацию, вы можете легко использовать статический инициализатор.

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

(извините за ответ вместо комментария к проголосовавшему потоку, у меня есть новая учетная запись без комментариев).