¿Por qué lanzar 2 excepciones seguidas no genera una advertencia de código inalcanzable?

¿Por qué las siguientes líneas de código no crean una advertencia de comstackción?

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

Según lo veo, el comstackdor debería informarle que la segunda excepción de lanzamiento no puede ser alcanzada.

Claramente es un error del comstackdor, y se introdujo en C # 3.0, justo en el momento en que refactoricé en gran medida el comprobador de accesibilidad. Esto es probablemente mi mal, lo siento.

El error es completamente benigno; básicamente, olvidamos un caso en el reportero de advertencia. Generamos la información de accesibilidad correctamente; como otros han notado, recortamos correctamente el código inalcanzable antes de codegen.

El error no es más que un caso perdido en el generador de advertencia. Tenemos un código complicado que garantiza que no informemos un trillón de advertencias cuando se hace inaccesible una gran parte del código. El comstackdor tiene un código para informar específicamente las advertencias en gotos incondicionales (“goto”, “break”, “continuar”), gotos condicionales (“if”, “while”, etc.), try-catch-finally (que incluye formularios equivalentes) try-catch-finally, como bloquear y usar), bloques, retornos (retorno de rendimiento y retorno regular), declaraciones locales, declaraciones etiquetadas, interruptores y declaraciones de expresión.

¿Ves “arrojar declaraciones” en esa lista? Yo tampoco. Eso es porque lo olvidamos.

Disculpas por los inconvenientes. Enviaré una nota a QA y obtendremos una solución para esto en una versión futura del idioma.

Gracias por traer esto a mi atención.

Podría dar un error / advertencia del comstackdor, pero lamentablemente no es así. Pero si miras el código IL solo se considera la primera excepción. Puede iniciar sesión en connect.microsoft.com y plantear esto como algo que le gustaría ver.

si usted ILDasm el código a continuación

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

Obtendrás esto

 .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 

Después del primer objeto Exception, nada más se convierte en IL.

Este error (como Lippert lo llama arriba) tiene algunas consecuencias extrañas. Por supuesto, código como este tampoco da advertencias en tiempo de comstackción:

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

Si eres creativo, aún puedes hacer que la instrucción throw induzca advertencias (no relacionadas). En este curioso ejemplo, el código genera una advertencia solo porque “verde” es inalcanzable:

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

(el código solo crea una instancia de delegado de un lambda e invoca al delegado).

Pero este ejemplo es más simple y parece peor:

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

¡Esta última muestra de código también comstack sin advertencia! No hay problema en “usar” neverAssigned porque el “uso” es inalcanzable. Pero tampoco recibe ninguna advertencia sobre una variable local nunca asignada a (y nunca “realmente” leída). Entonces, repito, sin advertencia alguna, lo cual parece muy incorrecto.

Me pregunto si este comportamiento cambiará en versiones futuras de Visual C #. Cambiarlo dará a las personas advertencias que antes no tenían (que en mi opinión merecen).

Además: Este comportamiento parece no haber cambiado con el comstackdor C # 6.0 basado en Roslyn de Visual Studio 2015.