unario operador equal entre ejemplos diferente diferencia comparar cadenas c# .net null overloading operator-keyword

c# - equal - Overriding== operador. Cómo comparar con nulo?



operador c# (9)

Posible duplicado:
¿Cómo verifico nulos en una sobrecarga de operador ''=='' sin recursión infinita?

Probablemente haya una respuesta fácil a esto ... pero parece eludirme. Aquí hay un ejemplo simplificado:

public class Person { public string SocialSecurityNumber; public string FirstName; public string LastName; }

Digamos que para esta aplicación en particular, es válido decir que si los números de la seguridad social coinciden, y ambos nombres coinciden, entonces nos estamos refiriendo a la misma "persona".

public override bool Equals(object Obj) { Person other = (Person)Obj; return (this.SocialSecurityNumber == other.SocialSecurityNumber && this.FirstName == other.FirstName && this.LastName == other.LastName); }

Para mantener las cosas consistentes, también anulamos los operadores == y! = Para los desarrolladores del equipo que no usan el método .Equals .

public static bool operator !=(Person person1, Person person2) { return ! person1.Equals(person2); } public static bool operator ==(Person person1, Person person2) { return person1.Equals(person2); }

Bien y elegante, ¿verdad?

Sin embargo, ¿qué sucede cuando un objeto Person es null ?

No puedes escribir

if (person == null) { //fail! }

Dado que esto causará que la anulación del operador == se ejecute, y el código fallará en:

person.Equals()

llamada a un método, ya que no puede invocar un método en una instancia nula.

Por otro lado, no se puede verificar explícitamente esta condición dentro de la anulación ==, ya que causaría una recursión infinita (y un desbordamiento de pila [punto com])

public static bool operator ==(Person person1, Person person2) { if (person1 == null) { //any code here never gets executed! We first die a slow painful death. } return person1.Equals(person2); }

Entonces, ¿cómo se anulan los operadores == y! = Para la igualdad de valores y se siguen contabilizando los objetos nulos?

Espero que la respuesta no sea dolorosamente simple. :-)


Emite la Persona a un Objeto y luego realiza la comparación:

object o1 = (object)person1; object o2 = (object)person2; if(o1==o2) //compare instances. return true; if (o1 == null || o2 == null) //compare to null. return false; //continue with Person logic.


Emitir la instancia de Person al object :

public static bool operator ==(Person person1, Person person2) { if ((object)person1 == (object)person2) return true; if ((object)person1 == null) return false; if ((object)person2 == null) return false; return person1.Equals(person2); }


La rutina final (hipotética) está por debajo. Es muy similar a la primera respuesta aceptada de @ cdhowie.

public static bool operator ==(Person person1, Person person2) { if (Person.ReferenceEquals(person1, person2)) return true; if (Person.ReferenceEquals(person1, null)) return false; //* return person1.Equals(person2); }

¡Gracias por las excelentes respuestas!

// * - .Equals() realiza la comprobación nula en person2


La sobrecarga de estos operadores consistentemente es bastante difícil. Mi respuesta a una pregunta relacionada puede servir como una plantilla.

Básicamente, primero necesita hacer una prueba de referencia ( object.ReferenceEquals ) para ver si el objeto es null . Entonces llamas a Equals .


Más fácil que cualquiera de esos enfoques sería simplemente usar

public static bool operator ==(Person person1, Person person2) { EqualityComparer<Person>.Default.Equals(person1, person2) }

Esto tiene la misma semántica de igualdad nula que los enfoques que todos los demás proponen, pero es el problema del marco averiguar los detalles :)


Siempre lo he hecho de esta manera (para los operadores == y! =) Y reutilizo este código para cada objeto que creo:

public static bool operator ==(Person lhs, Person rhs) { // If left hand side is null... if (System.Object.ReferenceEquals(lhs, null)) { // ...and right hand side is null... if (System.Object.ReferenceEquals(rhs, null)) { //...both are null and are Equal. return true; } // ...right hand side is not null, therefore not Equal. return false; } // Return true if the fields match: return lhs.Equals(rhs); }

"! =" dice así:

public static bool operator !=(Person lhs, Person rhs) { return !(lhs == rhs); }

Editar
== función de operador == para que coincida con la implementación sugerida de Microsoft here .


Use object.ReferenceEquals(person1, null) lugar del operador == :

public static bool operator ==(Person person1, Person person2) { if (object.ReferenceEquals(person1, null)) { return object.ReferenceEquals(person2, null); } return person1.Equals(person2); }


cdhowie está en el dinero con el uso de ReferenceEquals , pero vale la pena señalar que todavía puede obtener una excepción si alguien pasa null directamente a Equals . Además, si va a anular Equals , casi siempre vale la pena implementar IEquatable<T> así que tendría que hacerlo.

public class Person : IEquatable<Person> { /* more stuff elided */ public bool Equals(Person other) { return !ReferenceEquals(other, null) && SocialSecurityNumber == other.SocialSecurityNumber && FirstName == other.FirstName && LastName == other.LastName; } public override bool Equals(object obj) { return Equals(obj as Person); } public static bool operator !=(Person person1, Person person2) { return !(person1 == person2); } public static bool operator ==(Person person1, Person person2) { return ReferenceEquals(person1, person2) || (!ReferenceEquals(person1, null) && person1.Equals(person2)); } }

Y, por supuesto, nunca debes anular Equals y no anular GetHashCode()

public override int GetHashCode() { //I''m going to assume that different //people with the same SocialSecurityNumber are extremely rare, //as optimise by hashing on that alone. If this isn''t the case, change this return SocialSecurityNumber.GetHashCode(); }

También vale la pena señalar que la identidad implica igualdad (es decir, que para cualquier concepto válido de "igualdad" algo siempre es igual a sí mismo). Dado que las pruebas de igualdad pueden ser costosas y ocurren en bucles, y dado que comparar algo consigo mismo suele ser bastante común en el código real (especialmente si los objetos se pasan en varios lugares), puede valer la pena agregarlo como un atajo:

public bool Equals(Person other) { return !ReferenceEquals(other, null) && ReferenceEquals(this, other) || ( SocialSecurityNumber == other.SocialSecurityNumber && FirstName == other.FirstName && LastName == other.LastName ); }

La cantidad de una ventaja de acceso directo en ReferenceEquals(this, other) puede variar considerablemente dependiendo de la naturaleza de la clase, pero si vale la pena hacerlo o no es algo que siempre se debe considerar, entonces incluyo la técnica aquí .


siempre puedes anular y poner

(Object)(person1)==null

Me imagino que esto funcionaría, aunque no estoy seguro.