Есть ли какой-либо "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
.
Ответы
Ответ 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>();
(извините за ответ вместо комментария к проголосовавшему потоку, у меня есть новая учетная запись без комментариев).