elvis - operador and en c#
Operador de sobrecarga== versus Equals() (6)
Creo que el estándar es que para la mayoría de los tipos, .Equals verifica la similitud de los objetos, y el operador ==
verifica la igualdad de referencia.
Creo que la mejor práctica es que para los tipos inmutables, el operador ==
debe verificar la similitud, así como .Equals
. Y si desea saber si realmente son el mismo objeto, use .ReferenceEquals
. Ver la clase de String
C # para un ejemplo de esto.
Estoy trabajando en un proyecto de C # en el que, hasta ahora, he utilizado objetos y fábricas inmutables para garantizar que los objetos de tipo Foo
siempre puedan compararse para obtener la igualdad con ==
.
Foo
objetos Foo
no se pueden cambiar una vez creados, y la fábrica siempre devuelve el mismo objeto para un conjunto dado de argumentos. Esto funciona muy bien, y a lo largo de la base del código asumimos que ==
siempre funciona para verificar la igualdad.
Ahora necesito agregar algunas funciones que presenten un caso de ventaja para el que esto no siempre funcionará. Lo más fácil de hacer es sobrecargar el operator ==
para ese tipo, de modo que ninguno de los otros códigos en el proyecto deba cambiar. Pero esto me parece un olor de código: la sobrecarga del operator ==
y No es Equals
a Equals
parece extraño, y estoy acostumbrado a la convención de que ==
comprueba la igualdad de referencia, y Equals
verifica la igualdad de objetos (o cualquiera que sea el término).
¿Es esta una preocupación legítima o debo seguir adelante y sobrecargar al operator ==
?
Definitivamente huele. Al sobrecargar ==
debe asegurarse de que tanto Equals()
como GetHashCode()
también sean consistentes. Vea las pautas de MSDN .
Y la única razón por la que esto parece estar bien es que describe su tipo como inmutable.
Hay una gran diferencia entre la sobrecarga ==
y la anulación de Equals.
Cuando tengas la expresion
if (x == y) {
El método que se utilizará para comparar las variables x e y se decide en el momento de la compilación . Esta es la sobrecarga del operador. El tipo utilizado al declarar xey se usa para definir qué método se usa para compararlos. El tipo real dentro de x e y (es decir, una subclase o implementación de interfaz) es irrelevante. Considera lo siguiente.
object x = "hello";
object y = ''h'' + "ello"; // ensure it''s a different reference
if (x == y) { // evaluates to FALSE
y lo siguiente
string x = "hello";
string y = ''h'' + "ello"; // ensure it''s a different reference
if (x == y) { // evaluates to TRUE
Esto demuestra que el tipo usado para declarar las variables xey se usa para determinar qué método se usa para evaluar ==.
En comparación, Equals se determina en tiempo de ejecución según el tipo real dentro de la variable x. Igual es un método virtual en Objeto que otros tipos pueden, y lo hacen, anular. Por lo tanto, los dos ejemplos siguientes se evalúan como verdaderos.
object x = "hello";
object y = ''h'' + "ello"; // ensure it''s a different reference
if (x.Equals(y)) { // evaluates to TRUE
y lo siguiente
string x = "hello";
string y = ''h'' + "ello"; // ensure it''s a different reference
if (x.Equals(y)) { // also evaluates to TRUE
Muestra que muestra cómo implementar esto de acuerdo con las directrices de MSFT (a continuación). Tenga en cuenta que, al anular Equals, también debe anular GetHashCode (). Espero que esto ayude a la gente.
public class Person
{
public Guid Id { get; private set; }
public Person(Guid id)
{
Id = id;
}
public Person()
{
Id = System.Guid.NewGuid();
}
public static bool operator ==(Person p1, Person p2)
{
bool rc;
if (System.Object.ReferenceEquals(p1, p2))
{
rc = true;
}
else if (((object)p1 == null) || ((object)p2 == null))
{
rc = false;
}
else
{
rc = (p1.Id.CompareTo(p2.Id) == 0);
}
return rc;
}
public static bool operator !=(Person p1, Person p2)
{
return !(p1 == p2);
}
public override bool Equals(object obj)
{
bool rc = false;
if (obj is Person)
{
Person p2 = obj as Person;
rc = (this == p2);
}
return rc;
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
Para tipos inmutables, no creo que haya nada de malo en tener ==
sobrecargado para apoyar la igualdad de valores. Sin embargo, no creo que anularía ==
sin anular los Equals
para tener la misma semántica. Si anula ==
y necesita verificar la igualdad de referencia por algún motivo, puede usar Object.ReferenceEquals(a,b)
.
Según las mejores prácticas propias de Microsofts, el resultado del método Equals y la sobrecarga de igual (==) debe ser el mismo.
CA2224: la anulación es igual a la sobrecarga del operador es igual a