c# - sólo - 5 formas de verificación de igualdad en.net... ¿por qué? y que usar?
solo y sólo ejemplos (4)
Mientras aprendía .net (por c #), encontré 5 formas de verificar la igualdad entre los objetos.
- El método ReferenceEquals ().
- El método virtual Equals (). (System.Object)
- El método static Equals ().
- El método Equals de la interfaz IEquatable.
- El operador de comparación ==.
Mi pregunta es :
- ¿Por qué hay tantos métodos Equals () junto con el operador de comparación?
- ¿Cuál de los equivalentes virtuales Equals () o Equaltable Equal () de IEquatable se usará ... (digamos si usamos nuestras propias clases de colección)
El método ReferenceEquals ().
Esto se usa para probar si dos variables dadas apuntan (las referencias de símbolos) al mismo objeto. Es literalmente equivalente a ((object)a) == ((object)b)
. Si anula el operador de comparación ( ==
), ReferenceEquals
mantiene una forma de acceder al comportamiento predeterminado.
Sin embargo , si está tratando con un tipo de valor (por ejemplo, una estructura), esto siempre devolverá falso . Esto se debe a que los cuadros de comparación de cada tipo de valor a un nuevo objeto, por lo tanto, naturalmente, las referencias no serán iguales.
El método virtual Equals (). (System.Object)
Esta es la forma predeterminada de comparar semánticamente dos objetos (de cualquier tipo). Cada clase anula esto como lo deseen. Por defecto, es equivalente a una llamada CLR ( InternalEquals ) que básicamente compara las referencias de memoria.
Tenga en cuenta que si dos objetos devuelven verdadero para Equals()
entonces GetHashCode()
en cada uno de ellos debe ser igual . Sin embargo, si los códigos hash para dos objetos son de valor equivalente (es decir, obj1.GetHashCode() == obj2.GetHashCode()
) esto no significa que Equals()
es verdadero.
Su clase debería implementar Equals
y GetHashCode
como medio para distinguir instancias de clase, y debe implementar esto o el operador ==
(idealmente ambos) si es un tipo de valor.
Tenga en cuenta que, para los tipos de valor, el comportamiento Equals
predeterminado es el de ValueType.Equals()
que si mira en Reflector (o lee la descripción de MSDN ) usa la reflexión para comparar los miembros de las dos instancias de valores.
El método static Equals ().
Esto es equivalente a return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB)))
donde cada tipo se convierte en Object
para la prueba. Mi prueba muestra que los operadores de comparación sobrecargados son ignorados, pero su método Equals
se usará si los objetos no son nulos y no son la misma referencia. Como tal, a.Equals(b)
no necesariamente es igual a object.Equals(a, b)
(para los casos donde ((object)a) == ((object)b)
o bien aob es nulo).
El método Equals de la interfaz IEquatable.
IEquatable proporciona una forma de tratar la comparación de instancias de la misma clase especialmente. Habiendo dicho que su método Equals
debería manejar el comportamiento de la misma manera :
Si implementa Equals, también debe anular las implementaciones de clase base de Object.Equals (Object) y GetHashCode para que su comportamiento sea coherente con el del método IEquatable.Equals
Sin embargo, debes implementar IEquatable :
Para manejar la posibilidad de que los objetos de una clase se almacenen en una matriz o un objeto de colección genérico, es una buena idea implementar IEtabletable para que el objeto se pueda identificar y manipular fácilmente.
El operador de comparación ==
El operador de comparación de forma predeterminada devuelve verdadero cuando ambos objetos son de la misma referencia.
No se recomienda anular el operador de comparación a menos que se trate de un tipo de valor (en cuyo caso se recomienda, junto con el método Equals
) o un tipo de referencia inmutable que normalmente se compararía por valor (por ejemplo, string
). Siempre implemente !=
Al mismo tiempo (de hecho, obtengo un requires a matching operator ''!='' to also be defined
error si no lo hago).
Recursos:
- http://blogs.msdn.com/b/vijaysk/archive/2008/03/19/object-referenceequals-valuevar-valuevar-will-always-return-false.aspx
- InternalEquals
- http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx
- http://msdn.microsoft.com/en-us/library/2dts52z7.aspx
- http://msdn.microsoft.com/en-us/library/ms131190.aspx
- http://msdn.microsoft.com/en-us/library/ms173147(VS.80).aspx
- http://msdn.microsoft.com/en-us/library/ms182276(VS.80).aspx
1 - La referencia equivale a comprobar si dos variables de tipo de referencia (clases, no estructuras) están referidas a la misma dirección de memoria.
2 - El método virtual Equals () verifica si dos objetos son equivalentes. Digamos que tienes esta clase:
class TestClass{
public int Property1{get;set}
public int Property2{get;set}
public override bool Equals(object obj)
{
if (obj.GetType() != typeof(TestClass))
return false;
var convertedObj = (TestClass)obj;
return (convertedObj.Property1 == this.Property1 && convertedObj.Property2 == this.Property2);
}
}
y crea una instancia de 2 objetos de esa clase:
var o1 = new TestClass{property1 = 1, property2 = 2}
var o2 = new TestClass{property1 = 1, property2 = 2}
aunque los dos objetos no son la misma instancia de TestClass, la llamada a o1.Equals (o2) devolverá true.
3 - El método estático Equals se usa para manejar problemas cuando hay un valor nulo en la verificación. Imagina esto, por ejemplo:
TestClass o1 = null;
var o2 = new TestClass{property1 = 1, property2 = 2}
Si intentas esto:
o1.Equals(o2);
obtendrá una NullReferenceException, porque o1 apunta a nada. Para abordar este problema, haz esto:
Object.Equals (o1, o2);
Este método está preparado para manejar referencias nulas.
4 - La interfaz IEquatable es proporcionada por .Net, por lo que no es necesario hacer moldes dentro de su método Equals. Si el compilador descubre que ha implementado la interfaz en una clase para el tipo que está tratando de verificar para la igualdad, dará prioridad a ese método sobre el reemplazo de Object.Equals (Object). Por ejemplo:
class TestClass : IEquatable<TestClass>
{
public int Property1 { get; set; }
public int Property2 { get; set; }
public override bool Equals(object obj)
{
if (obj.GetType() != typeof(TestClass))
return false;
var convertedObj = (TestClass)obj;
return (convertedObj.Property1 == this.Property1 && convertedObj.Property2 == this.Property2);
}
#region IEquatable<TestClass> Members
public bool Equals(TestClass other)
{
return (other.Property1 == this.Property1 && other.Property2 == this.Property2);
}
#endregion
}
ahora si hacemos esto:
var o1 = new TestClass{property1 = 1, property2 = 2}
var o2 = new TestClass{property1 = 1, property2 = 2}
o1.Equals(o2);
El método llamado es Igual (TestClass), anterior a Equals (Object).
5 - El operador == generalmente significa lo mismo que ReferenceEquals, verifica si dos variables apuntan a la misma dirección de memoria. El problema es que este operador puede ser anulado para realizar otros tipos de controles. En strings, por ejemplo, verifica si dos instancias diferentes son equivalentes.
Este es un enlace útil para entender mejor las igualdades en .Net:
Cada versión de igualdad es ligeramente diferente.
Pruebas de ReferenceEquals
para la igualdad de referencia.
virtual Equals
de forma predeterminada comprueba la igualdad de referencia para los tipos de clase y la igualdad de valores para los tipos de estructura. Se puede anular para definir la igualdad de manera diferente, si se desea; y debe ser anulado para tipos de valores.
static Equals
simplemente llama a virtual Equals
, pero también permite argumentos null
.
IEquatable<T>.Equals
es un genérico / tipo seguro equivalente para virtual Equals
.
operator==
pretende ser igual a la virtual Equals
predeterminada, lo que significa igualdad de referencia para los tipos de clase (a menos que la clase también anule a otros operadores). También se debe anular para los tipos de valores.
Si escribe su propia clase de colección, use IEqualityComparer<T>
, por defecto, EqualityComparer<T>.Default
. No use ninguna de las comparaciones de igualdad directamente.
Para los primitivos, mantente con el operador ==.
En la mayoría de los objetos suministrados en .NET Framework y en cualquier objeto personalizado que usted cree, el método .Equals () y el operador == solo verificarán si dos objetos se refieren al mismo objeto en el montón.
El propósito de la interfaz IEquatable es anular el método .Equals () para cambiar su comportamiento de la comprobación de la igualdad referencial para verificar la igualdad de valores. El tipo System.String es un ejemplo de un objeto .NET incorporado que implementa esta interfaz.
El método .ReferenceEquals () proporciona una forma para que los desarrolladores que han anulado el método .Equals () estándar aún puedan verificar dos objetos para la igualdad referencial.