c# - operadores - ¿Cómo verifico nulos en una sobrecarga de operador ''=='' sin recursión infinita?
sobrecarga de operadores c# (10)
Lo siguiente causará 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?
Un error común en las sobrecargas del operador == es usar
(a == b)
,(a ==null)
o(b == null)
para verificar la igualdad de referencia. Esto en cambio da como resultado una llamada al operador sobrecargado ==, causando uninfinite loop
. UseReferenceEquals
o coloque el tipo en Object para evitar el ciclo.
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;
}
Pautas de referencia para Sobrecarga Equals () y Operador ==
Enviar 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);
}
Mi enfoque es hacer
(object)item == null
sobre lo cual confío en el operador de igualdad del objeto 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
en los 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 constante / no propenso a error de comprobación de nulos en todo. También he encontrado que el (object)item == null
es muy muy ligeramente más rápido que Object.ReferenceEquals(item, null)
, pero solo si importa (¡Actualmente estoy trabajando en algo donde tengo que optimizar todo! )
Para ver una guía completa sobre la implementación de verificaciones de igualdad, consulte ¿Qué es "Mejores prácticas" para comparar dos instancias de un Tipo de referencia?
Pruebe Object.ReferenceEquals(foo1, null)
De todos modos, no recomendaría sobrecargar el operador ==
; debe usarse para comparar referencias y usar Equals
para las comparaciones "semánticas".
Puede intentar usar una propiedad de objeto y capturar la NullReferenceException resultante. Si la propiedad que intentas es heredada o anulada 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;
}
Si está utilizando C # 7 o posterior, puede usar la coincidencia nula de patrones constantes:
public static bool operator==(Foo foo1, Foo foo2)
{
if (foo1 is null)
return foo2 is null;
return foo1.Equals(foo2);
}
Esto le da un código ligeramente más ordenado que el objeto que llama. ReferenceEquals (foo1, null)
Si he reemplazado bool Equals(object obj)
y quiero que el operador ==
y Foo.Equals(object obj)
devuelvan la misma respuesta, generalmente implemento el operador !=
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 de hacer todas las comprobaciones nulas para mí termina llamando a foo1.Equals(foo2)
que he anulado para hacer la comprobación real si las dos son iguales.
Use ReferenceEquals
. Desde los 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;
}
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);
}
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 sea null
para la 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étodoReferenceEquals
. Además, si tantoobjA
comoobjB
sonnull
, el método devuelvetrue
. - Determina si
objA
uobjB
esnull
. Si es así, devuelvefalse
. Si los dos objetos no representan la misma referencia de objeto y ninguno esnull
, llama aobjA.Equals(objB)
y devuelve el resultado. Esto significa que siobjA
anula elObject.Equals(Object)
, se llama a esta anulación.
.
public static bool operator ==(Foo objA, Foo objB) {
return Object.Equals(objA, objB);
}