c# - suplantacion - que hacer si usan mi identidad
Cómo usar la identidad de un objeto como clave para el Diccionario<K, V> (4)
¿Es posible utilizar un objeto como clave para un Dictonary<object, ...>
tal manera que el Diccionario trate los objetos como iguales solo si son idénticos?
Por ejemplo, en el código a continuación, quiero que la Línea 2 devuelva 11 en lugar de 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
La implementación actual del Diccionario utiliza object.Equals()
y object.GetHashCode()
en las claves; pero estoy buscando un tipo diferente de diccionario que use la identidad del objeto como una clave (en lugar del valor del objeto). ¿Existe tal Diccionario en .NET o tengo que implementarlo desde cero?
No necesita crear su propio diccionario, debe crear su propia implementación de IEqualityComparer<T>
que utiliza la identidad tanto para el hashing como para la igualdad. No creo que exista tal cosa en el marco, pero es bastante fácil de compilar debido a 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
}
}
He restringido que T
sea un tipo de referencia para que termines con objetos en el diccionario; Si usaste esto para tipos de valor, podrías obtener algunos resultados extraños. (No sé de antemano cómo funcionaría eso; sospecho que no lo haría).
Con eso en su lugar, el resto es fácil. Por ejemplo:
Dictionary<string, int> identityDictionary =
new Dictionary<string, int>(new IdentityEqualityComparer<string>());
Por supuesto, las otras respuestas son totalmente correctas, pero escribí mi propia versión para satisfacer mis necesidades:
/// <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);
}
}
Razón de diseño:
- La clase está
sealed
.Si la clase no está diseñada para ser extendida, voy a evitar todo ese gasto al sellarla.
- Eric LippertConozco a muchas personas (incluido yo mismo) que creen que las clases deberían estar selladas de forma predeterminada.
- Jon Skeet - Hay una propiedad de solo lectura estática de
Instance
para exponer una instancia única de esta clase. - Utiliza
Object.ReferenceEquals()
lugar de==
porqueReferenceEquals
es más explícito. - Utiliza
RuntimeHelpers.GetHashCode()
porque no quiero usar el códigoGetHashCode
del objeto, que posiblemente no se corresponda con el comportamiento deReferenceEquals
. Esto también evita una verificación nula. - Tiene documentacion.
Usa tu propio comparador de igualdad
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);
}
}
Tenga en cuenta que GetHashCode
se puede anular, pero la comprobación crucial se realiza con Equals
.
Utilice el Dictionary
con el IEqualityComparer<TKey>