Perché il lancio di 2 eccezioni in una riga non genera un avviso di codice irraggiungibile?

Perché le seguenti righe di codice non creano un avviso del compilatore?

void Main() { throw new Exception(); throw new Exception(); } 

A mio avviso, il compilatore dovrebbe informarti che non è ansible raggiungere l’eccezione del secondo tiro.

È chiaramente un bug del compilatore ed è stato introdotto in C # 3.0, proprio nel periodo in cui ho pesantemente refactato il correttore di raggiungibilità. Questo è probabilmente il mio cattivo, mi dispiace.

L’insetto è completamente benigno; in pratica, abbiamo appena dimenticato un caso nel reporter di avviso. Generiamo correttamente le informazioni sulla raggiungibilità; come altri hanno notato, ritagliamo correttamente il codice irraggiungibile prima di codegen.

Il bug non è altro che un caso mancante nel generatore di allerta. Abbiamo un codice complicato in là che garantisce che non segnaliamo un avviso di zillion quando si rende irraggiungibile una parte di codice estesa. Il compilatore ha il codice per segnalare in modo specifico gli avvisi su goto non condizionali (“goto”, “break”, “continua”), goto condizionale (“if”, “while” e così via), try-catch-finally (che include forms equivalenti per provare-catch-finally, come lock e using), blocchi, return (yield return e regular return), dichiarazioni locali, istruzioni etichettate, switch ed espressioni.

Vedi “lanciare dichiarazioni” su quella lista? Neanche io. Questo perché l’abbiamo dimenticato.

Scuse per l’inconveniente. Invierò una nota al QA e otterremo una correzione per questo in una versione futura della lingua.

Grazie per avermelo fatto notare.

Potrebbe dare un avvertimento / errore del compilatore ma purtroppo non lo fa. Ma se si guarda al codice IL, viene considerata solo la prima eccezione. È ansible accedere a connect.microsoft.com e sollevarlo come qualcosa che si desidera vedere.

se hai ILDasm il codice qui sotto

 static void Main(string[] args) { Console.Write("Line 1"); throw new Exception(); throw new Exception(); Console.Write("Line 4"); } 

Otterrai questo

 .method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 18 (0x12) .maxstack 8 IL_0000: nop IL_0001: ldstr "Line 1" IL_0006: call void [mscorlib]System.Console::Write(string) IL_000b: nop IL_000c: newobj instance void [mscorlib]System.Exception::.ctor() IL_0011: throw } // end of method Program::Main 

Dopo il primo object Exception, nient’altro viene convertito in IL.

Questo bug (come Lippert lo chiama in alto) ha alcune strane conseguenze. Ovviamente il codice come questo non fornisce alcun avviso in fase di compilazione:

 static int Main() { return 0; throw new Exception("Can you reach me?"); } 

Se sei creativo, puoi comunque fare in modo che l’istruzione throw induca avvisi (non correlati). In questo curioso esempio, il codice genera un avviso solo perché “verde” non è raggiungibile:

 static int Main() { return 0; throw new Exception(((Func)(() => { if (2 == 2) { return "yellow"; } return "green"; }))()); } 

(il codice crea semplicemente un’istanza delegata da un lambda e invoca il delegato).

Ma questo esempio è più semplice e sembra peggio:

 static int Main() { int neverAssigned; return 0; throw new Exception(neverAssigned.ToString()); } 

Questo ultimo esempio di codice viene compilato anche senza preavviso! Non c’è alcun problema in “using” neverAssigned perché “usage” è irraggiungibile. Ma non si avverte alcun avvertimento su una variabile locale mai assegnata (e mai “realmente” letta). Quindi, per ripetere, nessun avvertimento, che sembra molto sbagliato.

Mi chiedo se questo comportamento verrà modificato nelle versioni future di Visual C #? Cambiarlo darà alle persone avvertimenti che non avevano prima (che secondo me meritano).

Aggiunta: questo comportamento sembra essere invariato con il compilatore C # 6.0 basato su Roslyn di Visual Studio 2015.