2010-06-23 3 views
8

L'opérateur ?? en C# utilise-t-il un court-circuit lors de l'évaluation?L'opérateur `` ?? `` utilise-t-il un court-circuit?

var result = myObject ?? ExpressionWithSideEffects(); 

Lorsque myObject est non nul, le résultat de ExpressionWithSideEffects() n'est pas utilisé, mais ExpressionWithSideEffects() être totalement ignorée?

Répondre

7

Oui, c'est le cas. Comme toujours, la spécification du langage C# est la source définitive .

De C# 3 spécifications, l'article 7.12 (v3 plutôt que 4, comme la spécification v4 va dans les détails dynamiques qui ne sont pas vraiment pertinentes ici):

Le type de l'expression a ?? b dépend de les conversions implicites sont disponibles entre les types des opérandes. Par ordre de préférence, le type d'un? b est A0, A ou B, où A est le type de a, B est le type de b (à condition que b ait un type), et A0 est le type sous-jacent de A si A est un type Nullable, ou A sinon . Plus précisément, a ?? b est traité comme suit:

  • Si A est pas un type ou d'un type nullable de référence, une erreur de compilation se produit.
  • Si A est un type Nullable et qu'une conversion implicite existe de b à A0, le type de résultat est A0. A run-time, a est d'abord évalué. Si un n'est pas nul, a est déballé pour taper A0, et ceci devient le résultat. Sinon, b est évalué et est converti en type A0, ce qui devient le résultat .
  • Sinon, si une conversion implicite existe de b vers A, le type de résultat est A. Lors de l'exécution, a est d'abord évalué. Si a n'est pas nul, un devient le résultat . Sinon, b est évalué et est converti en type A, ce qui donne le résultat .
  • Sinon, si b a un type B et une conversion implicite existe de A0 à B, le type de résultat est B. Au moment de l'exécution, a est d'abord évalué. Si a n'est pas null, a est déballé au type A0 (sauf si A et A0 sont du même type) et converti en type B, et ceci devient le résultat. Sinon, b est évalué et devient le résultat.
  • Sinon, a et b sont incompatibles et une erreur de compilation se produit.

Les deuxième, troisième et quatrième puces sont les plus pertinentes.


Il y a une discussion philosophique à avoir de savoir si le compilateur vous arrive d'utiliser est la réelle source de vérité ... est la vérité d'une langue ce qu'il est signifiait faire ou que fait-il actuellement ?

+0

Pour la note de pied ... Je pense que c'est pourquoi nous aimons tous Eric Lippert étant autour :) –

+1

@Matthew: L'une des nombreuses raisons, oui. Un aspect intéressant d'Eric est qu'il peut agir comme l'incarnation humaine des spec * et * du compilateur ... –

10

Oui, il y a un court-circuit.

Voici un extrait de tester en LINQPad:

string bar = "lol"; 
string foo = bar ?? string.Format("{2}", 1); 
foo.Dump(); 
bar = null; 
foo = bar ?? string.Format("{2}", 1); 
foo.Dump(); 

Le premier fonctionne sans soudent lancer une exception alors que le second ne jette (la chaîne de format est invalide).

+0

merde, je peux me sentir être tiré dans l'horizon de l'événement! – Will

0

C'est pourquoi nous avons des tests unitaires.

[TestMethod] 
    public void ShortCircuitNullCoalesceTest() 
    { 
     const string foo = "foo"; 
     var result = foo ?? Bar(); 
     Assert.AreEqual(result, foo); 
    } 

    [TestMethod] 
    [ExpectedException(typeof(ArgumentException))] 
    public void ShortCircuitNullCoalesceFails() 
    { 
     const string foo = null; 
     var result = foo ?? Bar(); 
    } 

    private static string Bar() 
    { 
     throw new ArgumentException("Bar was called"); 
    } 

Ce ne sont pas les meilleurs noms de test, mais vous avez l'idée. Il montre que l'opérateur de coalescence nulle court-circuite comme prévu.

+0

Et je réalise que ArgumentException était un choix étrange, c'était juste le premier type d'exception à venir à l'esprit. – CaffGeek

+3

Ce n'est pas pour cela que nous avons des tests unitaires. C'est pourquoi nous avons des spécifications de langage. En particulier, si nous avions des tests unitaires mais aucune spécification de langue, nous ne saurions que ce qu'il se passe dans le cas testé. Si nous avions la spécification de la langue mais pas de tests unitaires, nous saurions quand même ce que la langue est censée faire dans le cas général. Certes, les tests unitaires permettent de vérifier que le compilateur implémente réellement la spécification de langage ... mais je préférerais toujours obtenir la spécification plutôt qu'un test unitaire pour des questions comme celle-ci. –

+0

@Jon Skeet, touche. J'aime toujours écrire des tests rapides pour vérifier des choses dont je ne suis pas sûr. Je ne vais pas nécessairement le garder. Et il est toujours possible que le compilateur ait implémenté la spécification de façon incorrecte ... – CaffGeek

Questions connexes