2008-09-30 695 views
17

Necesito hacer una comparación entre un objeto y NULL. Cuando el objeto no es NULL, lo lleno con algunos datos.El objeto C# no es nulo pero (myObject! = Null) aún devuelve falso

Aquí está el código:

if (region != null) 
{ 
    .... 
} 

Esto está trabajando pero cuando bucle y bucle en algún momento el objeto de región no es nulo (puedo ver los datos en su interior en el modo de depuración). Paso a paso al depurar, no entra dentro de la declaración IF ... Cuando hago un Quick Watch con la siguiente expresión: Veo que (region == null) devuelve false, AND (region! = Null)) devuelve falso también ... ¿por qué y cómo?

actualización

Alguien señalar que el objeto era == y = sobrecargado:

public static bool operator ==(Region r1, Region r2) 
    { 
     if (object.ReferenceEquals(r1, null)) 
     { 
      return false; 
     } 
     if (object.ReferenceEquals(r2, null)) 
     { 
      return false; 
     } 

     return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id); 
    } 


    public static bool operator !=(Region r1, Region r2) 
    { 
     if (object.ReferenceEquals(r1, null)) 
     { 
      return false; 
     } 
     if (object.ReferenceEquals(r2, null)) 
     { 
      return false; 
     } 
     return (r1.Cmr.CompareTo(r2.Cmr) != 0 || r1.Id != r2.Id); 
    } 

Respuesta

28

¿El operador == y/o! = Está sobrecargado para la clase del objeto de región?

Ahora que has publicado el código para las sobrecargas:

Las sobrecargas probablemente debería tener el siguiente aspecto (código tomado de publicaciones realizadas por Jon Skeet y Philip Rieck):

public static bool operator ==(Region r1, Region r2) 
{ 
    if (object.ReferenceEquals(r1, r2)) { 
     // handles if both are null as well as object identity 
     return true; 
    } 

    if ((object)r1 == null || (object)r2 == null) 
    { 
     return false; 
    }   

    return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id); 
} 

public static bool operator !=(Region r1, Region r2) 
{ 
    return !(r1 == r2); 
} 
+0

¡Me acabo de dar cuenta de que tengo == y! = Sobrecargado! –

+0

Creo que alguien cometió un error en la parte! = ¡Lo verifico! Thx por la pista. –

+0

Correcto, las sobrecargas son incorrectas: si copia el código o la explicación de mi publicación a continuación, eliminaré mi publicación –

3

Esto a veces puede suceder cuando usted tiene múltiples hilos que trabajan con los mismos datos. Si este es el caso, puede usar un candado para evitar que jueguen entre ellos.

+0

Thx, pero la razón es realmente la == y! = Que no estaba sobrecargada. Pero tu respuesta pudo haber sido correcta. –

16

Esos sobrecargas de operadores estan rotos.

En primer lugar, hace la vida mucho más fácil si! = Se implementa simplemente llamando == e invirtiendo el resultado.

En segundo lugar, antes de que los cheques de nulidad en == no debe haber:

if (object.ReferenceEquals(r1, r2)) 
{ 
    return true; 
} 
+0

OK Haré la modificación en unos minutos. –

0

Entonces, ¿es que estos controles no están bien aquí:

public static bool operator !=(Region r1, Region r2) 
{ 
    if (object.ReferenceEquals(r1, null)) 
    { 
     return false; 
    } 
    if (object.ReferenceEquals(r2, null)) 
    { 
     return false; 
    } 
... 
+0

Sí, necesita un cheque adicional de antemano, para dar cuenta del caso en que r1 y r2 son ambos nulos. Verifica mi respuesta. (Esto también optimiza el caso en el que r1 y r2 son ambos no nulos, pero se refieren al mismo objeto). –

7

Tanto de las sobrecargas son incorrectos

public static bool operator ==(Region r1, Region r2) 
    { 
     if (object.ReferenceEquals(r1, null)) 
     { 
      return false; 
     } 
     if (object.ReferenceEquals(r2, null)) 
     { 
      return false; 
     } 

     return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id); 
    } 

si r1 y r2 son nulos, la primera prueba (object.ReferenceEquals (r1, null)) devolverá falso, incluso aunque r2 también sea nulo.

tratar

//ifs expanded a bit for readability 
public static bool operator ==(Region r1, Region r2) 
    { 
     if((object)r1 == null && (object)r2 == null) 
     { 
      return true; 
     } 
     if((object)r1 == null || (object)r2 == null) 
     { 
      return false; 
     }   
     //btw - a quick shortcut here is also object.ReferenceEquals(r1, r2) 

     return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id); 
    } 
+0

Estoy realizando pruebas. dame 2 minutos –

+0

Esto está funcionando !!!!!!!! Aunque hubieras sido mi "respuesta aceptada", pero alguien más ha averiguado primero por qué y cómo :) –

0

Hay otra posibilidad que usted debe hacer clic en el icono de actualización junto al parámetro que está viendo. VS intentan mantenerse al día con el rendimiento sin evaluar cada declaración/parámetro. Eche un vistazo para asegurarse, antes de comenzar a hacer cambios en lugares que no son relevantes.

2

Por comparación de igualdad de un tipo "T", la sobrecarga de estos métodos:

int GetHashCode() //Overrides Object.GetHashCode 
bool Equals(object other) //Overrides Object.Equals; would correspond to IEquatable, if such an interface existed 
bool Equals(T other) //Implements IEquatable<T>; do this for each T you want to compare to 
static bool operator ==(T x, T y) 
static bool operator !=(T x, T y) 

Su código de comparación de tipo específico se debe hacer en un solo lugar: el métodoIEquatable<T> interfaz de tipo seguro Equals(T other). Si está comparando con otro tipo (T2), implemente también IEquatable<T2> y coloque el código de comparación de campo para ese tipo en Igual (T2 otro).

Todos los métodos y operadores sobrecargados deben enviar la tarea comparación de igualdad a las principales Iguales tipo-safe (t otro) método de instancia, de manera que una jerarquía de dependencia limpia se mantiene y garantías estrictas se introducen a cada nivel para eliminar la redundancia y no esencial complejidad.

bool Equals(object other) 
{ 
    if (other is T) //replicate this for each IEquatable<T2>, IEquatable<T3>, etc. you may implement 
     return Equals((T)other)); //forward to IEquatable<T> implementation 
    return false; //other is null or cannot be compared to this instance; therefore it is not equal 
} 

bool Equals(T other) 
{ 
    if ((object)other == null) //cast to object for reference equality comparison, or use object.ReferenceEquals 
     return false; 
    //if ((object)other == this) //possible performance boost, ONLY if object instance is frequently compared to itself! otherwise it's just an extra useless check 
     //return true; 
    return field1.Equals(other.field1) && 
      field2.Equals(other.field2); //compare type fields to determine equality 
} 

public static bool operator ==(T x, T y) 
{ 
    if ((object)x != null) //cast to object for reference equality comparison, or use object.ReferenceEquals 
     return x.Equals(y); //forward to type-safe Equals on non-null instance x 
    if ((object)y != null) 
     return false; //x was null, y is not null 
    return true; //both null 
} 

public static bool operator !=(T x, T y) 
{ 
    if ((object)x != null) 
     return !x.Equals(y); //forward to type-safe Equals on non-null instance x 
    if ((object)y != null) 
     return true; //x was null, y is not null 
    return false; //both null 
} 

Discusión:

La implementación anterior centraliza el tipo específico (es decir, la igualdad de campo) comparación con el final de la ejecución IEquatable<T> para el tipo. Los operadores == y != tienen una implementación paralela pero opuesta. Prefiero esto más que tener una referencia la otra, de modo que hay una llamada de método adicional para la dependiente. Si el operador != simplemente va a llamar al operador ==, en lugar de ofrecer un operador con el mismo rendimiento, entonces también puede usar !(obj1 == obj2) y evitar la llamada al método adicional. La comparación entre sí queda excluida del operador igual y de las implementaciones IEquatable<T>, porque puede presentar 1. una sobrecarga innecesaria en algunos casos, y/o 2. un rendimiento incoherente según la frecuencia con la que una instancia se compara a sí misma frente a otra instancias.

Una alternativa que no me gusta, pero debería mencionar, es invertir esta configuración, centralizando en su lugar el código de igualdad específico del tipo en el operador de igualdad y los métodos Equals dependen de eso. Uno podría usar el atajo de ReferenceEquals(obj1,obj2) para verificar la igualdad de referencia y la igualdad nula simultáneamente como lo mencionó Philip en una publicación anterior, pero esa idea es engañosa. Parece que estás matando a dos pájaros de un tiro, pero en realidad estás creando más trabajo: después de determinar que los objetos no son nulos ni tienen la misma instancia, entonces, además, tienes que verificar si cada instancia es nulo. En mi implementación, compruebas que una sola instancia sea nula exactamente una vez. En el momento en que se llama al método de instancia Equals, ya se ha descartado que el primer objeto que se compara sea nulo, por lo que todo lo que queda por hacer es comprobar si el otro es nulo. Entonces, después de como máximo dos comparaciones, saltamos directamente a la verificación de campo, sin importar qué método usemos (Equals(object),Equals(T),==,!=). Además, como mencioné, si realmente está comparando y objetando a sí mismo la mayoría de las veces, entonces podría agregar esa verificación en el método Equals justo antes de sumergirse en las comparaciones de campo. El último punto para agregarlo es que aún puede mantener la jerarquía de flujo/dependencia sin introducir una verificación redundante/inútil en cada nivel.

0
bool comp; 
if (object.IsNullOrEmpty(r1)) 
{ 
    comp = false; 
} 

if (object.IsNullOrEmpty(r2)) 
{ 
    comp = false; 
} 
return comp; 
+1

// te podría ayudar o ayudar a cualquiera que lo necesite – fernando

+2

No solo proporciones respuestas de solo código. –

Cuestiones relacionadas