2010-06-23 7 views
8

L'operatore ?? in C# utilizza cortocircuiti durante la valutazione?L'operatore `` ?? `` usa cortocircuiti?

var result = myObject ?? ExpressionWithSideEffects(); 

Quando myObject non è nullo, il risultato di ExpressionWithSideEffects() non viene utilizzato, ma ExpressionWithSideEffects() ignorato completamente?

risposta

7

Sì, sì. Come sempre, la specifica del linguaggio C# è la fonte definitiva .

Dalla C# 3 spec, sezione 7.12 (V3 anziché 4, come le specifiche v4 va in particolari dinamiche che non sono davvero rilevanti qui):

Il tipo dell'espressione a ?? b dipende da quale le conversioni implicite sono disponibili tra i tipi di operandi. In ordine di preferenza, il tipo di a ?? b è A0, A o B, dove A è il tipo di a, B è il tipo di b (ammesso che b abbia un tipo), e A0 è il tipo sottostante di A se A è un tipo nullable, o A altrimenti . Specificamente, a ?? b viene elaborata come segue:

  • Se A non è verifica un tipo annullabile o ad un tipo di riferimento, un errore di compilazione .
  • Se A è un tipo nullable e una conversione implicita esiste da b a A0, il tipo di risultato è A0. Al run-time, a viene prima valutato. Se un non è nullo, a viene scartato per digitare A0 e questo diventa il risultato. In caso contrario, viene valutata b e convertito in tipo A0, e questo diventa il risultato.
  • Altrimenti, se esiste una conversione implicita da b ad A, il tipo di risultato è A. In fase di esecuzione, viene prima valutato a. Se a non è nullo, a diventa il risultato . In caso contrario, viene valutata b e convertito in tipo A, e questo diventa il risultato.
  • In caso contrario, se b ha un tipo B e una conversione implicita esiste da A0 a B, il tipo di risultato è B. Al momento dell'esecuzione, viene valutato prima a. Se a non è null, a viene scartato per digitare A0 (a meno che A e A0 siano dello stesso tipo) e convertito in tipo B, e questo diventa il risultato. In caso contrario, b è valutato e diventa il risultato.
  • In caso contrario, aeb sono incompatibili e si verifica un errore in fase di compilazione.

Il secondo, terzo e quarto elenco sono i pertinenti.


C'è una discussione filosofica per essere avuto sul fatto che il compilatore vi capita di essere utilizzando è la effettiva fonte di verità ... è la verità su una lingua di cosa si tratta significava fare o cosa è attualmente ?

+0

Alla nota del piede ... Penso che sia per questo che tutti noi ci godiamo Eric Lippert in giro :) –

+1

@Matthew: uno dei tanti motivi, sì. Un aspetto interessante di Eric è che può agire come l'incarnazione umana sia della specifica * che * del compilatore ... –

10

Sì, è in cortocircuito.

Ecco un frammento di testare in LINQPad:

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

La prima si fondono funziona senza un'eccezione, mentre la seconda fa un tiro (la stringa di formato non è valido).

+0

merda, posso sentirmi trascinato nell'orizzonte degli eventi! – Will

0

Questo è il motivo per cui abbiamo collaudo dell'unità.

[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"); 
    } 

Questi non sono i migliori nomi di test, ma si ottiene l'idea. Mostra che i cortocircuiti dell'operatore di coalesce nullo come previsto.

+0

E mi rendo conto che ArgumentException è stata una scelta strana, è stato solo il primo tipo di eccezione a venire in mente. – CaffGeek

+3

Questo non è il motivo per cui abbiamo un test unitario. Questo è il motivo per cui abbiamo le specifiche della lingua. In particolare, se avessimo avuto test unitari ma non speculazioni linguistiche, avremmo solo saputo cosa succede nel caso in esame. Se avessimo le specifiche del linguaggio ma non i test di unità, tuttavia, sapremmo ancora che cosa si intende fare la lingua nel caso generale. Certo, i test unitari aiutano a verificare che il compilatore attui effettivamente le specifiche del linguaggio ... ma preferirei sempre raggiungere le specifiche piuttosto che un test unitario per domande come questa. –

+0

@Jon Skeet, touche. Mi piace ancora scrivere test rapidi per verificare cose di cui non sono sicuro. Non lo terrei necessariamente in giro. Ed è sempre possibile che il compilatore abbia implementato le specifiche in modo errato ... – CaffGeek