Comment vérifier les valeurs NULL dans une surcharge d'opérateur '==' sans récursion infinie?
-
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?
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éthodeReferenceEquals
. De plus, siobjA
etobjB
sontnull
, la méthode retournetrue
. - Détermine si
objA
ouobjB
estnull
. Si tel est le cas, il renvoiefalse
. Si les deux objets ne représentent pas la même référence d'objet, ninull
, il appelleobjA.Equals (objB)
et renvoie le résultat. Cela signifie que siobjA
remplace la méthodeObject.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 uneboucle infinie
. UtilisezReferenceEquals
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;
}