try - ¿El manejo de excepciones en C#contradice el estándar ECMA-335?
try catch c# messagebox (3)
Mi comprensión se basa en este artículo largo, pero fantástico, que admite el comportamiento enumerado en la especificación C #.
El estándar CLI (EMCA-335) muestra que si no hay una captura adecuada, el tiempo de ejecución debe terminar de inmediato. El tiempo de ejecución de .NET no hace esto, en cambio, parece inclinarse hacia el comportamiento de la especificación de C # (EMCA-334).
Primero, me parece extraño que una especificación de lenguaje parezca estar definiendo el comportamiento del marco. En segundo lugar, parecen contradecir.
- ¿Se contradicen entre sí o estoy entendiendo el significado incorrecto del documento?
- ¿El tiempo de ejecución tiene que ir por el manejo de excepciones de esta manera para cumplir con el estándar?
Como pregunta opcional, ¿cuál es la "correcta", como en, si tuviera que escribir mi propia implementación de la CLI, cuál debería usar? Tenga en cuenta que el documento EMCA-335 (CLI) se actualizó hace dos meses, en el que se actualizó EMCA-334 (C #) en 2006.
ECMA-335 Partition I Section 12.4.2.5
- Cuando se produce una excepción, la CLI busca en la matriz el primer bloque protegido que
- Protege una región que incluye el puntero de instrucción actual y
- Es un bloque de manipulador de captura y
- Cuyo filtro desea manejar la excepción
Si no se encuentra una coincidencia en el método actual, se busca el método de llamada, y así sucesivamente. Si no se encuentra ninguna coincidencia, la CLI volcará un seguimiento de pila y abortará el programa.
Si se encuentra una coincidencia, la CLI hace retroceder la pila hasta el punto que se acaba de localizar, pero esta vez llama a los manejadores de fallas y por último. A continuación, se inicia el controlador de excepción correspondiente.
Especificación C # §15.9.5 y §15.10 ( §8.9.5 y §8.10 en MSDN )
La principal diferencia entre este y el estándar CLI es que, independientemente de que se encuentre o no un bloque catch, la aplicación no solo existirá, sino que también desenrollará la pila y se encargará finalmente de los manejadores.
Sugeriría leer el estándar en sí mismo para obtener un mejor significado de esto, ya que a continuación hay un resumen muy crudo. Describe paso a paso cómo se ejecuta una instrucción try con cada escenario posible.
- En la función que plantea la excepción:
- Busca una cláusula catch coincidente en cada instrucción try
- Ejecuta la sentencia catch si existe
- Se ejecuta finalmente un bloque si existe.
- Si no hubiera un controlador, los pasos anteriores se repiten en la función de llamada
- Si el procesamiento de excepciones finaliza todas las invocaciones de miembros de funciones en el subproceso actual, lo que indica que el subproceso no tiene un controlador para la excepción, entonces el subproceso se termina. El impacto de dicha terminación está definido por la implementación.
Creo que esto podría ser simplemente una redacción vaga.
Si no se encuentra una coincidencia en el método actual, se busca el método de llamada, y así sucesivamente. Si no se encuentra ninguna coincidencia, la CLI volcará un seguimiento de pila y abortará el programa.
Está bien, eso es cierto en C #. Todos sabemos que si no tenemos una catch
, una excepción hará que nuestro programa se caiga.
Si se encuentra una coincidencia, la CLI hace retroceder la pila hasta el punto que se acaba de localizar, pero esta vez llama a los manejadores de fallas y por último. A continuación, se inicia el controlador de excepción correspondiente.
Y eso coincide con lo que sabemos de C # también. Si hay algunos bloques finally
(no podemos ver fault
) con los que lidiar a medida que subimos la pila desde la excepción que se lanza hasta nuestro bloque catch
, se procesan, pero se detiene allí y no va más arriba en la pila .
Mucho se cuelga de cómo leemos el "Si" que comienza el segundo extracto que acabo de citar. Lo estás leyendo como "si ... entonces ... de lo contrario no hay tal cosa". Sin embargo, se puede leer como el primer extracto que identifica el punto de la pila a la que se caminará: si hubo una catch
, entonces se caminó hasta ese punto. Si no hay una trampa, entonces se camina hasta la parte superior de la pila y obtenemos un volcado y un aborto. Los manejadores finalmente (y los manejadores de fallas) aún son llamados, pero el punto no es el de un manejador de captura coincidente.
Tu lectura es la más literal, y la mía la que estira las cosas un poco. Sin embargo, el mío coincide con la descripción de finally
en otro lugar en el mismo estándar, más estrechamente
El artículo citado en el OP tiene un supuesto subyacente incorrecto:
Por supuesto, no podemos hablar de excepciones administradas sin considerar primero el manejo estructurado de excepciones de Windows (SEH). Y también tenemos que mirar el modelo de excepción de C ++. Esto se debe a que tanto las excepciones administradas como las excepciones de C ++ se implementan sobre el mecanismo SEH subyacente, y porque las excepciones administradas deben interoperar con las excepciones de SEH y C ++.
El estándar CLR (ISO 23271 / ECMA 335) es intencionalmente agnóstico a la plataforma. La implementación de Microsoft es una de las muchas implementaciones posibles (Mono, por supuesto, siendo otra).
La interoperabilidad con el manejo estructurado de excepciones de Windows y el manejo de excepciones de C ++ es, estoy bastante seguro, la elección de Microsoft y no un requisito de ISO 23271.
No hay conflicto aquí. La especificación del lenguaje C # está redactada así:
Si la instrucción try no tiene cláusulas catch o si ninguna cláusula catch coincide con la excepción:
• Si la instrucción try tiene un bloque finally, se ejecuta el bloque finally.
• La excepción se propaga a la siguiente declaración de prueba adjunta.
La viñeta 2 aquí, especialmente , no dice lo que sucede cuando no hay una siguiente declaración de intento adjunta . Para eso, pasa al final de 8.9.5:
Si el procesamiento de excepciones finaliza todas las invocaciones de miembros de funciones en el subproceso actual, lo que indica que el subproceso no tiene un controlador para la excepción, entonces el subproceso se termina. El impacto de dicha terminación está definido por la implementación.
Ciertamente es la implementación definida. Más allá de la especificación Ecma 335, la política de manejo de excepciones es un elemento configurable en el CLR de Microsoft. Controlado por ICLRPolicyManager :: SetActionOnFailure (). A su vez, se puede configurar en el host predeterminado con el elemento de archivo <legacyUnhandledExceptionPolicy>
app.exe.config. El valor predeterminado para la versión 2.0 y superior de CLR es finalizar inmediatamente el programa.
Esto es, por lo demás, una hermenéutica bíblica bastante improductiva. Nada de esto debería ser una sorpresa para un programador de C #, especialmente teniendo en cuenta lo fácil que es probar.