Comment vérifier les valeurs NULL dans une surcharge d'opérateur '==' sans récursion infinie?

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

  •  09-06-2019
  •  | 
  •  

Question

Ce qui suit provoquera une récursion infinie sur la méthode de surcharge de l'opérateur ==

    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);
    }

Comment vérifier les valeurs nulles?

Était-ce utile?

La solution

Utilisez 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);
}

Autres conseils

Transformation en objet dans la méthode de surcharge:

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

Utilisez ReferenceEquals . À partir de Forums 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;
}

Essayez Object.ReferenceEquals (foo1, null)

Quoi qu'il en soit, je ne recommanderais pas de surcharger l'opérateur == ; il doit être utilisé pour comparer des références et utilisez est égal à pour "sémantique". comparaisons.

Si j'ai remplacé bool Equals (objet obj) et que je souhaite que l'opérateur == et Foo.Equals (objet obj) retourne la même réponse, j'implémente généralement l'opérateur ! = comme ceci:

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);
}

L'opérateur == , après avoir effectué tous les contrôles nuls pour moi, finira par appeler foo1.Equals (foo2) que j'ai forcé à effectuer le contrôle réel si les deux sont égaux.

Si vous utilisez C # 7 ou une version ultérieure, vous pouvez utiliser une correspondance de modèle constante nulle:

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

Cela vous donne un code légèrement plus ordonné que celui de l'appelant.ReferenceEquals (foo1, null)

Mon approche consiste à faire

(object)item == null

sur lequel je compte sur le propre opérateur d'égalité de objet qui ne peut pas se tromper. Ou une méthode d'extension personnalisée (et une surcharge):

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;
}

ou pour traiter plus de cas, peut être:

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

La contrainte empêche IsNull sur les types de valeur. Maintenant, c'est aussi doux que d'appeler

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

ce qui signifie que j’ai un seul style consistant à vérifier les valeurs NULL dans l’ensemble. J'ai également constaté que (objet) item == null est très très légèrement plus rapide que Objet. ReferenceEquals (item, null) , mais uniquement si cela compte (je travaille actuellement sur quelque chose qui nécessite de tout optimiser au maximum!).

Pour consulter un guide complet sur la mise en œuvre des contrôles d'égalité, voir Qu'est-ce qu'une" meilleure pratique "? Pour comparer deux instances d'un type de référence?

La méthode statique Equals (Object, Object) indique si deux objets, objA et objB , sont égaux. Il vous permet également de tester l’égalité des objets dont la valeur est null . Il compare objA et objB pour l'égalité, comme suit:

  • Détermine si les deux objets représentent la même référence d'objet. Si tel est le cas, la méthode retourne true . Ce test équivaut à appeler la méthode ReferenceEquals . De plus, si objA et objB sont null , la méthode retourne true .
  • Détermine si objA ou objB est null . Si tel est le cas, il renvoie false . Si les deux objets ne représentent pas la même référence d'objet, ni null , il appelle objA.Equals (objB) et renvoie le résultat. Cela signifie que si objA remplace la méthode Object.Equals (Object) , ce remplacement est appelé.

.

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

plus de réponses à opérateur surclassant comment comparer à null redirige ici comme un doublon.

Dans les cas où cela est fait pour prendre en charge les objets de valeur, je trouve la nouvelle notation trop pratique, et je tiens à vous assurer qu'il n'y a qu'un seul endroit où la comparaison est faite. Exploiter également Object.Equals (A, B) simplifie les contrôles null.

Ceci surchargera ==,! =, est égal à, et 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();

Pour les objets plus complexes, ajoutez des comparaisons supplémentaires dans Equals et un GetHashCode plus riche.

Il existe en fait un moyen plus simple de vérifier null dans ce cas:

if (foo is null)

C'est ça!

Cette fonctionnalité a été introduite en C # 7

  

Une erreur courante dans les surcharges de l'opérateur == consiste à utiliser (a == b) , (a == null) ou (b = = null) pour vérifier l'égalité de référence. Cette place     entraîne l'appel de l'opérateur surchargé ==, ce qui provoque une boucle infinie . Utilisez ReferenceEquals ou convertissez le type en objet pour éviter la    boucle.

consultez cette

// 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;
}

référence Consignes relatives à la surcharge égale () et opérateur ==

Vous pouvez essayer d’utiliser une propriété d’objet et attraper l’exception NullReferenceException qui en résulte. Si la propriété que vous essayez est héritée ou remplacée par Object, cela fonctionne pour toutes les classes.

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;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top