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

Ce qui suit provoquera une récursion infinie sur la méthode de surcharge d’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 puis-je vérifier les valeurs NULL?

Utilisez les équations de 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); } 

Cast pour objecter 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 des équations de ReferenceEquals . Depuis les 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 devrait être utilisé pour comparer des références et utiliser Equals pour des comparaisons “sémantiques”.

Si j’ai écrasé bool Equals(object obj) et que je veux que l’opérateur == et Foo.Equals(object obj) renvoient la même réponse, Foo.Equals(object obj) 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 == va alors, après avoir fait toutes les vérifications NULL pour moi, finir par appeler foo1.Equals(foo2) que j’ai foo1.Equals(foo2) pour faire la vérification réelle si les deux sont égaux.

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

 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 net que celui de l’object appelant.ReferenceEquals (foo1, null)

Mon approche est de faire

 (object)item == null 

sur lequel je me fie à l’opérateur d’égalité de l’object qui ne peut pas se tromper. Ou une méthode d’extension personnalisée (et une surcharge):

 public static bool IsNull(this T obj) where T : class { return (object)obj == null; } public static bool IsNull(this T? obj) where T : struct { return !obj.HasValue; } 

ou pour gérer plus de cas, peut être:

 public static bool IsNull(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 style de vérification cohérent / non sujet aux erreurs partout. J’ai aussi trouvé (object)item == null est très très très légèrement plus rapide que Object.ReferenceEquals(item, null) , mais seulement si c’est important (je travaille actuellement sur quelque chose où je dois tout micro-optimiser! ).

Pour consulter un guide complet sur la mise en œuvre des contrôles de l’égalité, voir Qu’est – ce que la «meilleure pratique» pour comparer deux instances d’un type de référence?

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

  • Il détermine si les deux objects représentent la même référence d’object. Si c’est le cas, la méthode renvoie true . Ce test équivaut à appeler la méthode ReferenceEquals . De plus, si objA et objB sont null , la méthode renvoie true .
  • Il détermine si objA ou objB est null . Si oui, il retourne false . Si les deux objects ne représentent pas la même référence d’object et qu’aucun n’est null , il appelle objA.Equals(objB) et renvoie le résultat. Cela signifie que si objA remplace la Object.Equals(Object) , cette substitution est appelée.

.

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

répondre plus à l’ opérateur de substitution comment comparer à null qui redirige ici en double.

Dans les cas où cela est fait pour prendre en charge les objects de valeur, je trouve la nouvelle notation à la scope de la main et je tiens à m’assurer qu’il n’y a qu’un seul endroit où la comparaison est faite. En outre, l’utilisation d’Object.Equals (A, B) simplifie les vérifications nulles.

Cela surchargera ==,! =, Equals 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 objects plus compliqués, ajoutez des comparaisons supplémentaires dans Equals et dans un GetHashCode plus riche.

Une erreur courante dans les surcharges d’opérateur == consiste à utiliser (a == b) , (a ==null) ou (b == null) pour vérifier l’égalité de référence. Cela se traduit par un appel à l’opérateur surchargé ==, provoquant une infinite loop . Utilisez ReferenceEquals ou convertissez le type en Object pour éviter la boucle.

Regarde ça

 // 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 Directives pour la surcharge d’Equals () et de l’opérateur ==

Vous pouvez essayer d’utiliser une propriété d’object et intercepter le NullReferenceException résultant. Si la propriété que vous essayez est héritée ou remplacée par Object, alors cela fonctionne pour n’importe quelle classe.

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