web-dev-qa-db-fra.com

Quelle est la différence entre "x est null" et "x == null"?

En C # 7 on peut utiliser

if (x is null) return;

au lieu de

if (x == null) return;

Y a-t-il des avantages à utiliser la nouvelle méthode (exemple précédent) par rapport à l'ancienne?

La sémantique est-elle différente?

Est-ce juste une question de goût? Si non, quand devrais-je utiliser l'un sur l'autre?

Référence: Nouveautés de C # 7. .

193
Maniero

Mise à jour: Le compilateur Roslyn a été mis à jour pour rendre le comportement des deux opérateurs identique lorsqu'il n'y a pas d'opérateur d'égalité surchargé. . Veuillez voir le code dans les résultats actuels du compilateur (_M1_ et _M2_ dans le code) qui montre ce qui se passe lorsqu'il n'y a pas de comparateur d'égalité surchargé. Ils ont tous les deux maintenant le comportement le plus performant _==_. S'il existe un comparateur d'égalité surchargé, le code est toujours différent .

Voir pour les anciennes versions du compilateur Roslyn l'analyse ci-dessous.


Pour null, il n'y a pas de différence avec ce à quoi nous sommes habitués avec C # 6. Cependant, les choses deviennent intéressantes lorsque vous changez null en une autre constante.

Prenons ceci par exemple:

_Test(1);

public void Test(object o)
{
    if (o is 1) Console.WriteLine("a");
    else Console.WriteLine("b");
}
_

Le test donne a. Si vous comparez cela à o == (object)1 ce que vous auriez écrit normalement, cela fait toute une différence. is prend en compte le type de l'autre côté de la comparaison. C'est cool!

Je pense que le modèle constant _== null_ et _is null_ est juste quelque chose de très familier "par accident", où la syntaxe de l'opérateur is et de l'opérateur égal aboutit au même résultat.


Comme svick commenté, is null_ APPELLE System.Object::Equals(object, object) OÙ _==_ APPELLE ceq .

IL pour is:

_IL_0000: ldarg.1              // Load argument 1 onto the stack
IL_0001: ldnull               // Push a null reference on the stack
IL_0002: call bool [mscorlib]System.Object::Equals(object, object) // Call method indicated on the stack with arguments
IL_0007: ret                  // Return from method, possibly with a value
_

IL pour _==_:

_IL_0000: ldarg.1              // Load argument 1 onto the stack
IL_0001: ldnull               // Push a null reference on the stack
IL_0002: ceq                  // Push 1 (of type int32) if value1 equals value2, else Push 0
IL_0004: ret                  // Return from method, possibly with a value
_

Puisque nous parlons de null, il n'y a pas de différence puisque this ne fait de différence que sur les instances . Cela pourrait changer si vous avez surchargé l'opérateur d'égalité.

167
Patrick Hofman

Il existe en fait une différence de sémantique entre les deux comparaisons. Le cas Edge se présente lorsque vous comparez null à un type qui a surchargé l'opérateur ==.

foo is null utilisera la comparaison de référence directe pour déterminer le résultat, alors que foo == null exécutera bien sûr l'opérateur surchargé == s'il existe.

Dans cet exemple, j'ai introduit un "bogue" dans l'opérateur surchargé ==, le forçant à toujours lever une exception si le deuxième argument est null:

void Main()
{
    Foo foo = null;

    if (foo is null) Console.WriteLine("foo is null"); // This condition is met
    if (foo == null) Console.WriteLine("foo == null"); // This will throw an exception
}

public class Foo
{
    public static bool operator ==(Foo foo1, Foo foo2)
    {
        if (object.Equals(foo2, null)) throw new Exception("oops");
        return object.Equals(foo1, foo2);
    }

    // ...
}

Le code IL pour foo is null utilise l'instruction ceq pour effectuer une comparaison de référence directe:

IL_0003:  ldloc.0     // foo
IL_0004:  ldnull      
IL_0005:  ceq

Le code IL pour foo == null utilise un appel à l'opérateur surchargé:

IL_0016:  ldloc.0     // foo
IL_0017:  ldnull      
IL_0018:  call        UserQuery+Foo.op_Equality

La différence est donc que si vous utilisez ==, vous risquez d'exécuter un code utilisateur (qui peut potentiellement avoir un comportement inattendu ou des problèmes de performances).

46