it-swarm-es.tech

¿Cómo verifico si hay nulos en una sobrecarga de operador '==' sin recursión infinita?

Lo siguiente causará una recursión 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 los nulos?

109
Andrew Jones

Use 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);
}
133
Abe Heidebrecht

Convierte 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);
}
19
Andrew Jones

Utilice ReferenceEquals. 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;
}
8
Jon Adams

Prueba 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".

4
Santiago Palladino

Si está utilizando C # 7 o posterior, puede usar la coincidencia de patrones constantes nulos:

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 limpio que el único objeto que realiza la llamada.

4
jacekbe

Si he anulado bool Equals(object obj) y quiero que el operador == Y Foo.Equals(object obj) devuelvan la misma respuesta, generalmente implemento el operador != De esta manera:

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 == Luego, después de hacer todas las verificaciones nulas para mí, terminará llamando foo1.Equals(foo2) que he anulado para hacer la verificación real si las dos son iguales.

4
Hallgrim

En realidad, hay una forma más simple de verificar contra null en este caso:

if (foo is null)

¡Eso es!

Esta característica se introdujo en C # 7

2
Reto Messerli

Mi enfoque es hacer

(object)item == null

en el que confío en el propio operador de igualdad de object 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, pueden ser:

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

La restricción impide IsNull en los tipos de valor. 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 consistente/no propenso a errores de verificar nulos en todo momento. También he encontrado que (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 donde debo ¡Micro-optimiza todo!).

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

1
nawfal

respondiendo más a anulando el operador cómo comparar con nulo que redirige aquí como un duplicado.

En los casos en que esto se hace para admitir objetos de valor, considero que la nueva notación es útil y me gusta asegurarme de que solo haya un lugar donde se haga la comparación. También aprovechando 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 rico.

0
CCondron

Para una sintaxis moderna y condensada:

public static bool operator ==(Foo x, Foo y)
{
    return x is null ? y is null : x.Equals(y);
}

public static bool operator !=(Foo x, Foo y)
{
    return x is null ? !(y is null) : !x.Equals(y);
}
0
mr5

El método estático Equals(Object, Object) indica si dos objetos, objA y objB, son iguales. También le permite probar objetos cuyo valor es null para igualdad. Compara objA y objB para 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 es equivalente a llamar al método ReferenceEquals. Además, si tanto objA como objB son null, el método devuelve true.
  • Determina si objA o objB es null. Si es así, devuelve false. Si los dos objetos no representan la misma referencia de objeto y ninguno es null, llama a objA.Equals(objB) y devuelve el resultado. Esto significa que si objA anula el método Object.Equals(Object), se llama a esta anulación.

.

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