web-dev-qa-db-fra.com

L'objet C # n'est pas null mais (myObject! = Null) renvoie toujours false

Je dois faire une comparaison entre un objet et NULL. Lorsque l'objet n'est pas NULL, je le remplis avec des données.

Voici le code:

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

Cela fonctionne, mais lors de la boucle, l'objet région n'est PAS null (je peux voir les données qu'il contient en mode débogage). Lors du débogage, pas à pas, il ne va pas à l'intérieur de l'instruction IF ... Lorsque je fais un tour d'horizon rapide avec les expressions suivantes: Je vois que (région == null) renvoie false, et (région! = Null ) renvoie false aussi ... pourquoi et comment?

Mettre à jour

Quelqu'un a fait remarquer que l'objet était == et! = Surchargé:

    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);
    }
17
Patrick Desjardins

L'opérateur == et/ou! = Est-il surchargé pour la classe de l'objet region?

Maintenant que vous avez posté le code pour les surcharges:

Les surcharges devraient probablement ressembler à ceci (code tiré des publications de Jon Skeet et 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);
}
28
Michael Burr

Les surcharges de l'opérateur sont brisées.

Premièrement, cela simplifie grandement la vie si! = Est mis en œuvre en appelant simplement == et en inversant le résultat.

Deuxièmement, avant l'enregistrement de la nullité ==, il devrait y avoir:

if (object.ReferenceEquals(r1, r2))
{
    return true;
}
16
Jon Skeet

Les deux surcharges sont incorrectes

 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 et r2 sont nuls, le premier test ( object.ReferenceEquals (r1, null) ) renverra false, même si r2 est également nul.

essayer

//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);
    }
7
Philip Rieck

Cela peut parfois arriver lorsque plusieurs threads travaillent avec les mêmes données. Si tel est le cas, vous pouvez utiliser un verrou pour les empêcher de s’embrouiller.

3
skb

Pour la comparaison d'égalité d'un type "T", surchargez ces méthodes:

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)

Votre code de comparaison spécifique à un type doit être placé à un endroit donné : la méthode d'interface IEquatable<T> sécurisée par le type Equals(T other). Si vous comparez à un autre type (T2), implémentez également IEquatable<T2> et mettez le code de comparaison de champs pour ce type est égal à (T2 autre).

Toutes les méthodes et tous les opérateurs surchargés doivent transmettre la tâche de comparaison d’égalité à la méthode d’instance principale Equals (T autre) sécurisée par type, de sorte qu’une hiérarchie des dépendances propres soit maintenue et que des garanties plus strictes soient introduites à chaque niveau pour éliminer la redondance et la complexité non essentielle.

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
}

Discussion:

L’implémentation précédente centralise la comparaison spécifique au type (égalité de champ) avec la fin de l’implémentation IEquatable<T> pour le type. Les opérateurs == et != ont une implémentation parallèle mais opposée. Je préfère cela plutôt que d’avoir l’une référence l’autre, de sorte qu’il existe un appel supplémentaire à la méthode pour la personne dépendante. Si l'opérateur != appelle simplement l'opérateur == au lieu d'offrir un opérateur tout aussi performant, vous pouvez également utiliser simplement !(obj1 == obj2) et éviter l'appel de méthode supplémentaire. La comparaison à soi est omise. de l'opérateur égal et des implémentations IEquatable<T>, car il peut introduire 1. une surcharge inutile dans certains cas, et/ou 2. des performances incohérentes selon la fréquence à laquelle une instance est comparée à elle-même par rapport à d'autres instances.

Une alternative que je n'aime pas, mais que je devrais mentionner, consiste à inverser cette configuration, en centralisant le code d'égalité spécifique au type dans l'opérateur d'égalité et en laissant les méthodes Equals en dépendre. On pourrait alors utiliser le raccourci de ReferenceEquals(obj1,obj2) pour vérifier simultanément l’égalité de référence et l’égalité nulle, comme Philip l’a mentionné dans un précédent article, mais cette idée est trompeuse. On dirait que vous tuez deux oiseaux avec une pierre, mais que vous créez en fait plus de travail - après avoir déterminé que les objets ne sont ni à la fois nuls et identiques, vous devrez ensuite, ENCORE, vérifier si chaque instance est nul. Dans mon implémentation, vous vérifiez qu'une seule instance est nulle une seule fois. Au moment où la méthode d'instance Equals est appelée, il est déjà exclu que le premier objet comparé soit nul, il ne reste donc qu'à vérifier si l'autre est nul. Donc, après au plus deux comparaisons, nous passons directement à la vérification sur le terrain, quelle que soit la méthode utilisée (Equals(object),Equals(T),==,!=). En outre, comme je l'ai mentionné, si vous comparez et vous objectez vraiment la plupart du temps, vous pouvez alors ajouter cette vérification dans la méthode Egalité juste avant de plonger dans les comparaisons sur le terrain. La dernière chose à ajouter est que vous pouvez toujours conserver la hiérarchie flux/dépendances sans introduire de contrôle redondant/inutile à tous les niveaux.

2
Triynko

Donc, est-ce que ces contrôles ici ne sont pas corrects:

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

Il existe une autre possibilité que vous deviez cliquer sur l'icône d'actualisation en regard du paramètre que vous surveillez. Les VS essaient de suivre la performance sans évaluer tous les énoncés/paramètres. Jetez un coup d'œil pour vous assurer, avant de commencer à modifier des lieux qui ne sont pas pertinents.

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

if (object.IsNullOrEmpty(r2))
{
    comp = false;
}
return comp;
0
fernando