web-dev-qa-db-fra.com

Pourquoi voit-on souvent "null! = Variable" au lieu de "variable! = Null" en C #?

En c #, y a-t-il une différence dans la vitesse d'exécution pour l'ordre dans lequel vous énoncez la condition?

if (null != variable) ...
if (variable != null) ...

Depuis récemment, j'ai vu le premier assez souvent, et il a retenu mon attention depuis que j'étais habitué au second.

S'il n'y a pas de différence, quel est l'avantage du premier?

98
mr_georg

C'est un maintien de C. En C, si vous utilisez un mauvais compilateur ou si les avertissements ne sont pas suffisamment élevés, cela se compilera sans aucun avertissement (et c'est en effet un code légal):

// Probably wrong
if (x = 5)

quand vous vouliez probablement dire

if (x == 5)

Vous pouvez contourner cela en C en faisant:

if (5 == x)

Une faute de frappe ici entraînera un code non valide.

Maintenant, en C #, c'est tout piffle. Sauf si vous comparez deux valeurs booléennes (ce qui est rare, IME), vous pouvez écrire le code plus lisible, car une instruction "if" nécessite une expression booléenne pour commencer, et le type de "x=5" est Int32, pas Boolean.

Je suggère que si vous voyez cela dans le code de vos collègues, vous les éduquez dans les manières des langues modernes, et leur suggérez d'écrire la forme la plus naturelle à l'avenir.

155
Jon Skeet

Il y a une bonne raison d'utiliser null en premier: if(null == myDuck)

Si votre class Duck Remplace l'opérateur ==, Alors if(myDuck == null) peut entrer dans une boucle infinie.

L'utilisation de null utilise d'abord un comparateur d'égalité par défaut et fait réellement ce que vous vouliez.

(J'entends que vous vous habituez à lire du code écrit de cette façon - je n'ai tout simplement pas encore expérimenté cette transformation).

Voici un exemple:

public class myDuck
{
    public int quacks;
    static override bool operator ==(myDuck a, myDuck b)
    {
        // these will overflow the stack - because the a==null reenters this function from the top again
        if (a == null && b == null)
            return true;
        if (a == null || b == null)
            return false;

        // these wont loop
        if (null == a && null == b)
            return true;
        if (null == a || null == b)
            return false;
        return a.quacks == b.quacks; // this goes to the integer comparison
    }
}
12
DanW

Comme tout le monde l'a déjà noté, cela vient plus ou moins du langage C où vous pourriez obtenir un faux code si vous oubliez accidentellement le deuxième signe égal. Mais il y a une autre raison qui correspond également à C #: la lisibilité.

Prenez simplement cet exemple simple:

if(someVariableThatShouldBeChecked != null
   && anotherOne != null
   && justAnotherCheckThatIsNeededForTestingNullity != null
   && allTheseChecksAreReallyBoring != null
   && thereSeemsToBeADesignFlawIfSoManyChecksAreNeeded != null)
{
    // ToDo: Everything is checked, do something...
}

Si vous voulez simplement échanger tous les mots null au début, vous pouvez repérer plus facilement toutes les vérifications:

if(null != someVariableThatShouldBeChecked
   && null != anotherOne
   && null != justAnotherCheckThatIsNeededForTestingNullity
   && null != allTheseChecksAreReallyBoring
   && null != thereSeemsToBeADesignFlawIfSoManyChecksAreNeeded)
{
    // ToDo: Everything is checked, do something...
}

Cet exemple est donc peut-être un mauvais exemple (reportez-vous aux directives de codage), mais pensez simplement à faire défiler rapidement un fichier de code complet. En voyant simplement le motif

if(null ...

vous savez immédiatement ce qui va suivre.

Si c'est l'inverse, vous devez toujours scan à la fin de la ligne pour voir le contrôle de nullité, vous laissant juste trébucher pendant une seconde pour savoir quel type de contrôle est effectué là-bas. . Peut-être que la mise en évidence de la syntaxe peut vous aider, mais vous êtes toujours plus lent lorsque ces mots clés sont à la fin de la ligne au lieu du début.

9
Oliver

Je suppose que c'est un programmeur C qui a changé de langue.

En C, vous pouvez écrire ce qui suit:

int i = 0;
if (i = 1)
{
    ...
}

Notez l'utilisation d'un seul signe égal à cet endroit, ce qui signifie que le code affectera 1 à la variable i, puis retournera 1 (une affectation est une expression) et utilisez 1 dans l'instruction if, qui sera traitée comme vraie. En d'autres termes, ce qui précède est un bug.

En C # cependant, ce n'est pas possible. Il n'y a en effet aucune différence entre les deux.

Je ne vois aucun avantage à suivre cette convention. En C, où les types booléens n'existent pas, il est utile d'écrire

if( 5 == variable)

plutôt que

if (variable == 5)

parce que si vous oubliez l'un des signes eaqual, vous vous retrouvez avec

if (variable = 5)

qui attribue 5 à variable et évalue toujours à vrai. Mais en Java, un booléen est un booléen. Et avec! =, Il n'y a aucune raison.

Un bon conseil, cependant, est d'écrire

if (CONSTANT.equals(myString))

plutôt que

if (myString.equals(CONSTANT))

car cela permet d'éviter les exceptions NullPointerExceptions.

Mon conseil serait de demander une justification de la règle. S'il n'y en a pas, pourquoi le suivre? Cela n'aide pas la lisibilité

4
Gokkula Sudan R

Autrefois, les gens oubliaient le '!' (ou le supplément "=" pour l'égalité, qui est plus difficile à repérer) et effectuez une affectation au lieu d'une comparaison. mettre le null devant élimine la possibilité du bogue, puisque null n'est pas une valeur l (c'est-à-dire qu'il ne peut pas être attribué).

La plupart des compilateurs modernes donnent un avertissement lorsque vous effectuez une affectation dans un conditionnel de nos jours, et C # donne en fait une erreur. La plupart des gens s'en tiennent au schéma var == null car il est plus facile à lire pour certaines personnes.

4
Rik

Pour moi, ça a toujours été le style que vous préférez

@Shy - Là encore, si vous confondez les opérateurs, vous devriez vouloir obtenir une erreur de compilation ou vous exécuterez du code avec un bogue - un bogue qui reviendra et vous mordra plus tard car il a produit un comportement inattendu

0
TheCodeJunkie