Как использовать идентификатор объекта в качестве ключа для словаря<K, V>
Можно ли использовать объект в качестве ключа для Dictonary<object, ...>
таким образом, что словарь рассматривает объекты как равные, только если они идентичны?
Например, в приведенном ниже коде я хочу, чтобы строка 2 возвращала 11 вместо 12:
Dictionary<object, int> dict = new Dictionary<object, int>();
object a = new Uri("http://www.google.com");
object b = new Uri("http://www.google.com");
dict[a] = 11;
dict[b] = 12;
Console.WriteLine(a == b); // Line 1. Returns False, because a and b are different objects.
Console.WriteLine(dict[a]); // Line 2. Returns 12
Console.WriteLine(dict[b]); // Line 3. Returns 12
Текущая реализация словаря использует object.Equals()
а также object.GetHashCode()
на ключах; но я ищу другой вид словаря, который использует идентификатор объекта в качестве ключа (вместо значения объекта). Есть ли такой словарь в.NET или я должен реализовать его с нуля?
5 ответов
Вам не нужно создавать свой собственный словарь - вам нужно создать свою собственную реализацию IEqualityComparer<T>
который использует идентичность для хеширования и равенства. Я не думаю, что такая вещь существует в рамках, но это достаточно легко построить из-заRuntimeHelpers.GetHashCode
,
public sealed class IdentityEqualityComparer<T> : IEqualityComparer<T>
where T : class
{
public int GetHashCode(T value)
{
return RuntimeHelpers.GetHashCode(value);
}
public bool Equals(T left, T right)
{
return left == right; // Reference identity comparison
}
}
Я ограничил T
быть ссылочным типом, так что вы будете в конечном итоге с объектами в словаре; если вы используете это для типов значений, вы можете получить некоторые странные результаты. (Я не знаю, как это будет работать; я подозреваю, что это не так.)
С этим на месте, остальное легко. Например:
Dictionary<string, int> identityDictionary =
new Dictionary<string, int>(new IdentityEqualityComparer<string>());
Конечно, другие ответы совершенно верны, но я написал свою собственную версию, чтобы удовлетворить мои потребности:
/// <summary>
/// An equality comparer that compares objects for reference equality.
/// </summary>
/// <typeparam name="T">The type of objects to compare.</typeparam>
public sealed class ReferenceEqualityComparer<T> : IEqualityComparer<T>
where T : class
{
#region Predefined
private static readonly ReferenceEqualityComparer<T> instance
= new ReferenceEqualityComparer<T>();
/// <summary>
/// Gets the default instance of the
/// <see cref="ReferenceEqualityComparer{T}"/> class.
/// </summary>
/// <value>A <see cref="ReferenceEqualityComparer<T>"/> instance.</value>
public static ReferenceEqualityComparer<T> Instance
{
get { return instance; }
}
#endregion
/// <inheritdoc />
public bool Equals(T left, T right)
{
return Object.ReferenceEquals(left, right);
}
/// <inheritdoc />
public int GetHashCode(T value)
{
return RuntimeHelpers.GetHashCode(value);
}
}
Обоснование дизайна:
- Класс
sealed
,Если класс не предназначен для расширения, я собираюсь избежать всех этих расходов, закрыв его.
- Эрик ЛиппертЯ знаю многих людей (включая меня), которые считают, что классы действительно должны быть запечатаны по умолчанию.
- Джон Скит - Есть
Instance
статическое свойство только для чтения, чтобы выставить единственный экземпляр этого класса. - Оно использует
Object.ReferenceEquals()
вместо==
так какReferenceEquals
более явно. - Оно использует
RuntimeHelpers.GetHashCode()
потому что я не хочу использовать возможно переопределенныйGetHashCode
объекта, который может не соответствовать поведениюReferenceEquals
, Это также позволяет избежать нулевой проверки. - Есть документация.
Начиная с 5.0, ReferenceEqualityComparer
теперь поставляется со средой выполнения.
Используйте свой собственный сравнитель равенства
public class ObjectIdentityEqualityComparer : IEqualityComparer<object>
{
public int GetHashCode(object o)
{
return o.GetHashCode();
}
public bool Equals(object o1, object o2)
{
return object.ReferenceEquals(o1, o2);
}
}
Обратите внимание, что GetHashCode
может быть отменено, но критическая проверка выполняется с Equals
,