Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/294.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如果finally块抛出异常会发生什么?_C#_Exception_Exception Handling_Try Catch Finally - Fatal编程技术网

C# 如果finally块抛出异常会发生什么?

C# 如果finally块抛出异常会发生什么?,c#,exception,exception-handling,try-catch-finally,C#,Exception,Exception Handling,Try Catch Finally,如果finally块抛出异常,会发生什么 具体来说,如果异常在finally块的中途抛出,会发生什么情况。该块中的其余语句(after)是否被调用 我知道异常会向上传播 异常被传播。它引发异常;)您可以在其他catch子句中捕获该异常 如果finally块抛出异常,到底发生了什么 该异常会向外和向上传播,并将(可以)在更高级别上处理 您的finally块将而不是在抛出异常的点之外完成 如果finally块在处理早期异常期间执行,那么第一个异常将丢失 C#4语言规范§8.9.5:如果finally

如果finally块抛出异常,会发生什么

具体来说,如果异常在finally块的中途抛出,会发生什么情况。该块中的其余语句(after)是否被调用


我知道异常会向上传播

异常被传播。

它引发异常;)您可以在其他catch子句中捕获该异常

如果finally块抛出异常,到底发生了什么

该异常会向外和向上传播,并将(可以)在更高级别上处理

您的finally块将而不是在抛出异常的点之外完成

如果finally块在处理早期异常期间执行,那么第一个异常将丢失

C#4语言规范§8.9.5:如果finally块引发另一个异常,则终止对当前异常的处理

CodeA和CodeB引发的异常的处理方式是相同的


最后,在
块中抛出的异常没有什么特殊之处,请将其视为代码B抛出的异常。

对于此类问题,我通常在Visual Studio中打开一个空的控制台应用程序项目,并编写一个小示例程序:

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");
        }
    }
}
运行程序时,您将看到执行
catch
最后执行
块的确切顺序。请注意,引发异常后finally块中的代码将不会执行(事实上,在此示例程序中,Visual Studio甚至会警告您它已检测到无法访问的代码):

从输出中可以看到,内部异常“丢失”(即忽略):

内端块 外部catch块处理从finally块引发的异常。 外挡块
如果有一个异常挂起(当
try
块有一个
finally
但没有
catch
时),新的异常将替换该异常


如果没有异常挂起,它的工作原理与在
finally
块之外抛出异常一样。

在另一个异常处于活动状态时抛出异常将导致第一个异常被第二个(稍后的)异常替换

下面是一些代码,说明了发生的情况:

    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);
        }
    }
  • 运行代码,您将看到“第二个异常”
  • 取消对try和catch语句的注释,您将看到“FirstException”
  • 同时取消对投掷的注释;语句,您将再次看到“第二个异常”

几个月前,我也遇到过类似的情况

    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();
        }
为了解决这个问题,我创建了一个实用类

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;
        }
    }
}

但是,如果您想使用参数和返回类型,那是另一回事

我必须这样做,以捕获一个错误,试图关闭一个由于异常而从未打开的流

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();
    }
}
如果创建了webRequest,但在

using (var sw = webRequest.GetRequestStream())
然后,finally将捕获一个异常,该异常试图关闭它认为已打开的连接,因为webRequest已创建

如果finally内部没有try-catch,则在清理webRequest时,此代码将导致未处理的异常

if (webRequest.GetRequestStream() != null) 
代码将从此处退出,而不会正确处理所发生的错误,从而导致调用方法出现问题

希望这有助于作为一个例子来保存“原始异常”(在
try
block中抛出)并牺牲“最终异常”(在
finally
block中抛出),以防原始异常对您更重要:

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

执行上述代码时,“原始异常”会向上传播到调用堆栈,而“最终异常”会丢失。

异常会向上传播,应在更高级别上处理。如果未在更高级别处理异常,则应用程序将崩溃。“finally”块执行在抛出异常的点停止

无论是否存在异常,“finally”块都保证执行

  • 如果在try块中发生异常后执行“finally”块

  • 如果这个异常没有得到处理

  • 如果finally块抛出异常

  • 然后,try块中发生的原始异常将丢失

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

    @bitbonk:像往常一样,从里到外。你能详细说明一下吗?你说异常是一样的是什么意思?因为你在你的内部捕获中抛出了异常,所以在这种情况下永远不会到达“内部最终块”example@TheofanisPantelides:不,将(几乎)始终执行
    finally
    块,在这种情况下,内部finally块也是如此(只需自己尝试示例程序)(如果出现不可恢复的异常,例如
    EngineeExecutionException
    ,则不会执行finally块,但在这种情况下,您的程序将立即终止)。但是,我不知道在第一段代码的第一个catch中抛出的角色是什么。我在控制台应用程序中使用和不使用它进行了尝试,没有发现任何差异。@johnpan:重点是要显示finally块始终执行,即使try和catch块都抛出异常。实际上,控制台输出没有任何差异put。为什么不试试呢?但在这类事情上,我最喜欢的是在finally之前返回,然后从finally块中返回其他内容。:)finally块中的所有语句都必须执行。它不能有返回。值得注意的是,可以清除“严重的”只能在特定代码块外捕获的异常,以引发在其中捕获和处理的异常。使用异常筛选器(可在vb.net中使用,但不是C#)可以检测到这种情况。代码无法检测到很多异常
    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();
        }
    }
    
    using (var sw = webRequest.GetRequestStream())
    
    if (webRequest.GetRequestStream() != null) 
    
    try
    {
        throw new Exception("Original Exception");
    }
    finally
    {
        try
        {
            throw new Exception("Finally Exception");
        }
        catch
        { }
    }
    
    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");
            }
        }
    }