¿Cómo puedo comprobar si hay valores nulos en una sobrecarga del operador '==' sin recursividad infinita?

StackOverflow https://stackoverflow.com/questions/73713

  •  09-06-2019
  •  | 
  •  

Pregunta

Lo siguiente provocará una recursividad infinita en el método de sobrecarga del operador ==

    Foo foo1 = null;
    Foo foo2 = new Foo();
    Assert.IsFalse(foo1 == foo2);

    public static bool operator ==(Foo foo1, Foo foo2) {
        if (foo1 == null) return foo2 == null;
        return foo1.Equals(foo2);
    }

¿Cómo verifico si hay nulos?

¿Fue útil?

Solución

Usar ReferenceEquals:

Foo foo1 = null;
Foo foo2 = new Foo();
Assert.IsFalse(foo1 == foo2);

public static bool operator ==(Foo foo1, Foo foo2) {
    if (object.ReferenceEquals(null, foo1))
        return object.ReferenceEquals(null, foo2);
    return foo1.Equals(foo2);
}

Otros consejos

Convertir a objeto en el método de sobrecarga:

public static bool operator ==(Foo foo1, Foo foo2) {
    if ((object) foo1 == null) return (object) foo2 == null;
    return foo1.Equals(foo2);
}

Usar ReferenciaEs igual.Desde el Foros de MSDN:

public static bool operator ==(Foo foo1, Foo foo2) {
    if (ReferenceEquals(foo1, null)) return ReferenceEquals(foo2, null);
    if (ReferenceEquals(foo2, null)) return false;
    return foo1.field1 == foo2.field2;
}

Intentar Object.ReferenceEquals(foo1, null)

De todos modos, no recomendaría sobrecargar el ==operador;debe usarse para comparar referencias y usar Equals para comparaciones "semánticas".

Si he anulado bool Equals(object obj) y quiero el operador == y Foo.Equals(object obj) para devolver la misma respuesta, normalmente implemento el != operador así:

public static bool operator ==(Foo foo1, Foo foo2) {
  return object.Equals(foo1, foo2);
}
public static bool operator !=(Foo foo1, Foo foo2) {
  return !object.Equals(foo1, foo2);
}

El operador == Entonces, después de hacer todas las comprobaciones nulas, terminaré llamando. foo1.Equals(foo2) que he anulado para hacer la verificación real si los dos son iguales.

Si está utilizando C# 7 o posterior, puede utilizar la coincidencia de patrones constante nula:

public static bool operator==(Foo foo1, Foo foo2)
{
    if (foo1 is null)
        return foo2 is null;
    return foo1.Equals(foo2);
}

Esto le proporciona un código un poco más claro que el que llama al objeto.ReferenceEquals(foo1, null)

Mi enfoque es hacer

(object)item == null

en el que estoy confiando objectEl propio operador de igualdad que no puede salir mal.O un método de extensión personalizado (y una sobrecarga):

public static bool IsNull<T>(this T obj) where T : class
{
    return (object)obj == null;
}

public static bool IsNull<T>(this T? obj) where T : struct
{
    return !obj.HasValue;
}

o para manejar más casos, puede ser:

public static bool IsNull<T>(this T obj) where T : class
{
    return (object)obj == null || obj == DBNull.Value;
}

La restricción impide IsNull sobre tipos de valores.Ahora es tan dulce como llamar

object obj = new object();
Guid? guid = null; 
bool b = obj.IsNull(); // false
b = guid.IsNull(); // true
2.IsNull(); // error

lo que significa que tengo un estilo coherente/no propenso a errores para comprobar si hay nulos en todo momento.yo también he encontrado (object)item == null es muy, muy, ligeramente más rápido que Object.ReferenceEquals(item, null), pero solo si es importante (¡actualmente estoy trabajando en algo en lo que tengo que microoptimizar todo!).

Para ver una guía completa sobre la implementación de controles de igualdad, consulte ¿Cuál es la "mejor práctica" para comparar dos instancias de un tipo de referencia?

La estática Equals(Object, Object) método indica si dos objetos, objA y objB, son iguales.También le permite probar objetos cuyo valor es null por la igualdad.se compara objA y objB por la igualdad de la siguiente manera:

  • Determina si los dos objetos representan la misma referencia de objeto.Si lo hacen, el método devuelve true.Esta prueba equivale a llamar al ReferenceEquals método.Además, si ambos objA y objB son null, el método devuelve true.
  • Determina si objA o objB es null.Si es así, regresa false.Si los dos objetos no representan la misma referencia de objeto y tampoco lo es null, llama objA.Equals(objB) y devuelve el resultado.Esto significa que si objA anula el Object.Equals(Object) método, se llama a esta anulación.

.

public static bool operator ==(Foo objA, Foo objB) {
    return Object.Equals(objA, objB);
}

respondiendo más a operador primordial cómo comparar con nulo eso redirige aquí como un duplicado.

En los casos en los que esto se hace para admitir objetos de valor, la nueva notación me resulta útil y me gusta asegurarme de que solo haya un lugar donde se realice la comparación.Además, aprovechar Object.Equals(A, B) simplifica las comprobaciones nulas.

Esto sobrecargará ==, !=, Equals y GetHashCode

    public static bool operator !=(ValueObject self, ValueObject other) => !Equals(self, other);
    public static bool operator ==(ValueObject self, ValueObject other) => Equals(self, other);
    public override bool Equals(object other) => Equals(other as ValueObject );
    public bool Equals(ValueObject other) {
        return !(other is null) && 
               // Value comparisons
               _value == other._value;
    }
    public override int GetHashCode() => _value.GetHashCode();

Para objetos más complicados, agregue comparaciones adicionales en Equals y un GetHashCode más completo.

En realidad, existe una forma más sencilla de comparar null en este caso:

if (foo is null)

¡Eso es todo!

Esta característica se introdujo en C# 7.

Un error común en las sobrecargas del operador == es usar (a == b), (a ==null), o (b == null) para comprobar la igualdad de referencia.esto en cambio resultados en una llamada al operador sobrecargado ==, provocando un infinite loop.Usar ReferenceEquals o arrojar el tipo a objeto, para evitar el bucle.

mira esto

// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))// using ReferenceEquals
{
    return true;
}

// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))// using casting the type to Object
{
    return false;
}

referencia Directrices para sobrecargar Equals() y Operador ==

Puede intentar utilizar una propiedad de objeto y detectar la NullReferenceException resultante.Si la propiedad que prueba se hereda o se anula de Object, entonces esto funciona para cualquier clase.

public static bool operator ==(Foo foo1, Foo foo2)
{
    //  check if the left parameter is null
    bool LeftNull = false;
    try { Type temp = a_left.GetType(); }
    catch { LeftNull = true; }

    //  check if the right parameter is null
    bool RightNull = false;
    try { Type temp = a_right.GetType(); }
    catch { RightNull = true; }

    //  null checking results
    if (LeftNull && RightNull) return true;
    else if (LeftNull || RightNull) return false;
    else return foo1.field1 == foo2.field2;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top