C# 如果finally块抛出异常会发生什么?
如果finally块抛出异常,会发生什么 具体来说,如果异常在finally块的中途抛出,会发生什么情况。该块中的其余语句(after)是否被调用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
我知道异常会向上传播 异常被传播。它引发异常;)您可以在其他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");
}
}
}