Si un bloque finally se lanza una excepción, lo que exactamente sucede?

Específicamente, ¿qué sucede si se produce la excepción a mitad de camino a través de un bloque finally. El resto de declaraciones (después) en este bloque se invoca?

Soy consciente de que las excepciones se propaga hacia arriba.

  • ¿Por qué no probarlo? Pero en este tipo de cosas, el que me gusta más es volver antes de que finalmente y, a continuación, devolver algo a los demás, desde el bloque finally. 🙂
  • Todas las declaraciones en un bloque finally se debe ejecutar. No puede tener un retorno. msdn.microsoft.com/en-us/library/0hbbzekw(VS.80).aspx
InformationsquelleAutor Jack Kada | 2010-05-26

11 Comentarios

  1. 414

    Si un bloque finally se produce una excepción de lo que exactamente sucede ?

    De que la excepción se propaga hacia afuera y hacia arriba, y se (puede) ser manejados a un nivel superior.

    Su bloque finally no ser completado más allá del punto donde se produce la excepción.

    Si el bloque finally se ejecuta durante el manejo de una excepción anterior luego de que la primera excepción se pierde.

    C# 4 de la Especificación del Lenguaje § 8.9.5: Si el bloque finally se lanza otra excepción, el procesamiento de la excepción actual está terminada.

    • +1: la única respuesta que completo responde a la pregunta
    • A menos que sea un ThreadAbortException, a continuación, todo el bloque finally se terminó la primera, ya que es una sección crítica.
    • tienes razón, pero que sólo se aplica a «ciertos asincrónica excepciones», es decir, ThreadAbortException. Para el normal 1-código de subproceso mi respuesta tiene.
    • «La primera excepción se pierde» – eso, en realidad es muy decepcionante, accasionally me parece IDisposable objetos que lanzar la excepción en Dispose(), que como resultado de excepción se perdió en el interior de «uso» de la cláusula.
    • «me parece IDisposable objetos que lanzar la excepción en Dispose()» – eso es raro, por decir lo menos. Leer en MSDN: EVITAR lanzar una excepción dentro de Dispose(bool) excepto en …
    • Si Dispose se llama en un arroyo que está abierto para la escritura, y los datos no pueden ser escritas, habiendo Dispose error silenciosamente podría ser peligroso, especialmente si no es la excepción estará pendiente después de la Dispose devuelve. Desafortunadamente, no hay manera de que Dispose saber si se trata de ser llamado en un using bloque que se ha realizado correctamente o que no se ha podido, y por lo tanto no hay manera de evitar clobbering cualquier excepción que pueda estar pendiente de cuando Dispose se llama, o esconder peligroso silencio errores si se producen problemas cuando no es la excepción está pendiente.
    • sí, «Disco lleno» errores puede ser muy difícil de encontrar y desentrañar en esta edad de Tera Discos. Pero cuando un «feliz» ruta de Disponer pone en ese lugar, todavía debe ceder ante el error anterior. No es ideal, pero la única cosa sensata que hacer.
    • Disco completo de los errores no son muy comunes en conectados directamente al disco duro principal, pero en ocasiones, los programas de escritura de archivos extraíbles o discos en red; los problemas pueden ser mucho más común con las personas. Si alguien sacan una memoria USB antes de que un archivo ha sido escrito completamente, sería mejor decir de inmediato que esperar hasta llegar a donde se va y busca el archivo está dañado. Ceder a la anterior error cuando hay un puede ser conveniente comportamiento, pero cuando no hay ningún error anterior sería mejor para informar del problema que dejarlo no declarada.

  2. 98

    Para preguntas como estas yo normalmente abierto hasta el vacío de un proyecto de aplicación de consola en Visual Studio y escribir un pequeño programa de ejemplo:

    using System;
    
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                try
                {
                    throw new Exception("exception thrown from try block");
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Inner catch block handling {0}.", ex.Message);
                    throw;
                }
                finally
                {
                    Console.WriteLine("Inner finally block");
                    throw new Exception("exception thrown from finally block");
                    Console.WriteLine("This line is never reached");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Outer catch block handling {0}.", ex.Message);
            }
            finally
            {
                Console.WriteLine("Outer finally block");
            }
        }
    }

    Cuando se ejecuta el programa, verá el orden exacto en que catch y finally bloques son ejecutados. Por favor, tenga en cuenta que el código en el bloque finally después de la excepción lanzada no se ejecutará (de hecho, en este programa de ejemplo de Visual Studio advertirle de que se ha detectado código inalcanzable):

    Interior del bloque catch manejo de la excepción del bloque try. 
    Interior por último bloque 
    Bloque catch externo manejo de la excepción del bloque finally. 
    Exterior por último bloque 
    

    Observación Complementaria

    Como Michael Damatov señalado, una excepción de la try bloque se «come» si no se manejan en un (interior) catch bloque. De hecho, en el ejemplo anterior, el re-lanzada excepción no aparece en el exterior del bloque catch. Para hacer aún más clara en los siguientes ligeramente modificada de la muestra:

    using System;
    
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                try
                {
                    throw new Exception("exception thrown from try block");
                }
                finally
                {
                    Console.WriteLine("Inner finally block");
                    throw new Exception("exception thrown from finally block");
                    Console.WriteLine("This line is never reached");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Outer catch block handling {0}.", ex.Message);
            }
            finally
            {
                Console.WriteLine("Outer finally block");
            }
        }
    }

    Como se puede ver en la salida de la excepción interna es «perdidos» (es decir, se omite):

    Interior por último bloque 
    Bloque catch externo manejo de la excepción del bloque finally. 
    Exterior por último bloque 
    
    • Debido a LANZAR la Excepción en el interior de la captura, ‘Interior del bloque finally’ nunca será alcanzada en este ejemplo
    • Pantelides: No, un finally bloque (casi) siempre se ejecutará, esto es, también en este caso por el interior del bloque finally (sólo tratar el programa de ejemplo de sí mismo (Un bloque finally no se ejecutará en el caso de un no-recuperable excepción, por ejemplo, un EngineExecutionException, pero en tal caso, el programa terminará inmediatamente de todos modos).
    • +1: Una respuesta útil que simplemente citando la especificación.
    • No veo cuál es el papel para el lanzamiento de la primera captura de su primera pieza de código, sin embargo. He probado con y sin ella, con una aplicación de consola, no differece encontrado.
    • El punto era demostrar que el bloque finally siempre se ejecuta, incluso si ambos try y catch bloque de lanzar una excepción. En realidad, no existe diferencia en la salida de la consola.
  3. 10

    Si hay una excepción pendiente (cuando el try bloque tiene una finally pero no catch), la nueva excepción que reemplaza uno.

    Si no hay ninguna excepción pendientes, funciona igual de lanzar una excepción fuera de la finally bloque.

    • Una excepción podría también estar pendientes de si hay es una coincidencia catch bloque que (re)produce una excepción.
  4. 2

    Rápido (y más que obvios) fragmento de salvar «a excepción original» (lanzado en try bloque) y el sacrificio «finalmente excepción» (lanzado en finally bloque), en caso de que el original es más importante para usted:

    try
    {
        throw new Exception("Original Exception");
    }
    finally
    {
        try
        {
            throw new Exception("Finally Exception");
        }
        catch
        { }
    }

    Cuando el código anterior, se realiza el «Original» Excepción se propaga hasta la pila de llamadas, y «Finalmente Excepción» se pierde.

  5. 2

    Tenía que hacer esto para la captura de un error tratando de cerrar una secuencia que nunca fue abierto a causa de una excepción.

    errorMessage = string.Empty;
    
    try
    {
        byte[] requestBytes = System.Text.Encoding.ASCII.GetBytes(xmlFileContent);
    
        webRequest = WebRequest.Create(url);
        webRequest.Method = "POST";
        webRequest.ContentType = "text/xml;charset=utf-8";
        webRequest.ContentLength = requestBytes.Length;
    
        //send the request
        using (var sw = webRequest.GetRequestStream()) 
        {
            sw.Write(requestBytes, 0, requestBytes.Length);
        }
    
        //get the response
        webResponse = webRequest.GetResponse();
        using (var sr = new StreamReader(webResponse.GetResponseStream()))
        {
            returnVal = sr.ReadToEnd();
            sr.Close();
        }
    }
    catch (Exception ex)
    {
        errorMessage = ex.ToString();
    }
    finally
    {
        try
        {
            if (webRequest.GetRequestStream() != null)
                webRequest.GetRequestStream().Close();
            if (webResponse.GetResponseStream() != null)
                webResponse.GetResponseStream().Close();
        }
        catch (Exception exw)
        {
            errorMessage = exw.ToString();
        }
    }

    si el webRequest fue creado, pero es un error de conexión que sucedió durante la

    using (var sw = webRequest.GetRequestStream())

    a continuación, la que finalmente se captura una excepción tratando de cerrar las conexiones cree que se abren debido a la webRequest había sido creado.

    Si finalmente no tienen un try-catch en el interior, este código podría causar una excepción no controlada durante la limpieza de la webRequest

    if (webRequest.GetRequestStream() != null) 

    desde allí el código de salida sin el manejo adecuado de la de error que ha ocurrido y por lo tanto causando problemas por el método de llamada.

    Espero que esta ayuda como un ejemplo

  6. 1

    Lanzar una excepción, mientras que otra excepción, se activa el resultado será la primera excepción llegar reemplazado por el segundo (después) de la excepción.

    Aquí está el código que ilustra lo que sucede:

        public static void Main(string[] args)
        {
            try
            {
                try
                {
                    throw new Exception("first exception");
                }
                finally
                {
                    //try
                    {
                        throw new Exception("second exception");
                    }
                    //catch (Exception)
                    {
                        //throw;
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }
    • Ejecutar el código y verás que la «segunda excepción»
    • Elimine el try y catch y verás que la «primera excepción»
    • También elimine el tiro; la declaración y verás que la «segunda excepción» de nuevo.
    • Vale la pena señalar que es posible que la limpieza de una «severa» de excepción que sólo serían capturados fuera de un determinado bloque de código para lanzar una excepción que se detecta y controla dentro de ella. El uso de filtros de excepción (disponible en vb.net, aunque no en C#) es posible detectar esta condición. No hay mucho que el código que se puede hacer para «manejar», aunque si uno es el uso de cualquier tipo de registro de marco es casi sin duda vale la pena el registro. El C++ enfoque de tener excepciones que se producen dentro de la limpieza de desencadenar un colapso del sistema es feo, pero después de haber excepciones desaparecer en mi humilde opinión es horrible.
  7. 1

    Hace unos meses también me enfrentaba a algo como esto,

        private  void RaiseException(String errorMessage)
        {
            throw new Exception(errorMessage);
        }
    
        private  void DoTaskForFinally()
        {
            RaiseException("Error for finally");
        }
    
        private  void DoTaskForCatch()
        {
            RaiseException("Error for catch");
        }
    
        private  void DoTaskForTry()
        {
            RaiseException("Error for try");
        }
    
    
            try
            {
                /*lacks the exception*/
                DoTaskForTry();
            }
            catch (Exception exception)
            {
                /*lacks the exception*/
                DoTaskForCatch();
            }
            finally
            {
                /*the result exception*/
                DoTaskForFinally();
            }

    Para resolver tal problema hice una clase de utilidad como

    class ProcessHandler : Exception
    {
    private enum ProcessType
    {
    Try,
    Catch,
    Finally,
    }
    private Boolean _hasException;
    private Boolean _hasTryException;
    private Boolean _hasCatchException;
    private Boolean _hasFinnallyException;
    public Boolean HasException { get { return _hasException; } }
    public Boolean HasTryException { get { return _hasTryException; } }
    public Boolean HasCatchException { get { return _hasCatchException; } }
    public Boolean HasFinnallyException { get { return _hasFinnallyException; } }
    public Dictionary<String, Exception> Exceptions { get; private set; } 
    public readonly Action TryAction;
    public readonly Action CatchAction;
    public readonly Action FinallyAction;
    public ProcessHandler(Action tryAction = null, Action catchAction = null, Action finallyAction = null)
    {
    TryAction = tryAction;
    CatchAction = catchAction;
    FinallyAction = finallyAction;
    _hasException = false;
    _hasTryException = false;
    _hasCatchException = false;
    _hasFinnallyException = false;
    Exceptions = new Dictionary<string, Exception>();
    }
    private void Invoke(Action action, ref Boolean isError, ProcessType processType)
    {
    try
    {
    action.Invoke();
    }
    catch (Exception exception)
    {
    _hasException = true;
    isError = true;
    Exceptions.Add(processType.ToString(), exception);
    }
    }
    private void InvokeTryAction()
    {
    if (TryAction == null)
    {
    return;
    }
    Invoke(TryAction, ref _hasTryException, ProcessType.Try);
    }
    private void InvokeCatchAction()
    {
    if (CatchAction == null)
    {
    return;
    }
    Invoke(TryAction, ref _hasCatchException, ProcessType.Catch);
    }
    private void InvokeFinallyAction()
    {
    if (FinallyAction == null)
    {
    return;
    }
    Invoke(TryAction, ref _hasFinnallyException, ProcessType.Finally);
    }
    public void InvokeActions()
    {
    InvokeTryAction();
    if (HasTryException)
    {
    InvokeCatchAction();
    }
    InvokeFinallyAction();
    if (HasException)
    {
    throw this;
    }
    }
    }

    Y utilizado como esta

    try
    {
    ProcessHandler handler = new ProcessHandler(DoTaskForTry, DoTaskForCatch, DoTaskForFinally);
    handler.InvokeActions();
    }
    catch (Exception exception)
    {
    var processError = exception as ProcessHandler;
    /*this exception contains all exceptions*/
    throw new Exception("Error to Process Actions", exception);
    }

    pero si usted desea utilizar parámetros y tipos de retorno que es otra historia

  8. 1
    public void MyMethod()
    {
    try
    {
    }
    catch{}
    finally
    {
    CodeA
    }
    CodeB
    }

    La forma en que las excepciones lanzadas por La y CodeB se maneja es la misma.

    Una excepción en un finally bloque tiene nada de especial, lo tratan como la excepción tirar por el código B.

    • Podría usted comentar? ¿A qué te refieres con las excepciones son el mismo?
    • lo siento, véase mi EDICIÓN
  9. 1

    La excepción se propaga, y debe ser manejado en un nivel superior. Si la excepción no se controla en el nivel superior, la aplicación se bloquea. El bloque «finally» la ejecución se detiene en el punto donde se produce la excepción.

    Independientemente de si se produce una excepción o no «finalmente» bloque está garantizado a ejecutar.

    1. Si la «finalmente» bloque se ejecuta después de que se ha producido una excepción en el bloque try,

    2. y si esa excepción no se controla

    3. y si el bloque finally se lanza una excepción

    A continuación, el original de la excepción que se produjo en el bloque try se pierde.

    public class Exception
    {
    public static void Main()
    {
    try
    {
    SomeMethod();
    }
    catch (Exception ex)
    {
    Console.WriteLine(ex.Message);
    }
    }
    public static void SomeMethod()
    {
    try
    {
    //This exception will be lost
    throw new Exception("Exception in try block");
    }
    finally
    {
    throw new Exception("Exception in finally block");
    }
    }
    } 

    Gran artículo para obtener más Detalles

  10. -1

    Se produce una excepción 😉 Usted puede capturar esa excepción en algún otro retén de la cláusula.

Dejar respuesta

Please enter your comment!
Please enter your name here