catch 块中的异常意味着 finally 块永远不会执行?
Exception in catch block means the finally block never executes?
我在 C# 中有一个简单的 try-catch-finally 块。据我了解,"finally" 块很有用,因为即使在 catch 块内抛出异常(除非有一些特殊的异常类型),它的代码也会执行。
但是,在下面的简单示例中,finally 块永远不会执行。 Visual Studio 说我的 catch 块中发生了未处理的异常,然后程序终止。我以为执行只会跳转到 finally 块。
如何保证finally块中的代码在catch块发生异常时执行?
public static void Main(string[] args)
{
try
{
throw new Exception("Apple");
}
catch (Exception ex)
{
throw new Exception("Banana");
}
finally
{
// This line never executes. Why?
Console.WriteLine("Carrot");
}
}
你抛出了第二个异常,没有捕获,第二个异常将不会继续代码..
Unhandled Exception: System.Exception: Banana
我建议你处理你的第一个异常,而不是抛出另一个。
static void Main(string[] args)
{
var x = 2;
try
{
if(x >1) throw new Exception("Apple");
}
catch (Exception ex)
{
x = 1;
}
finally
{
Console.WriteLine("Carrot");
}
}
如果您想了解更多关于异常处理的信息,RTFM:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/exception-handling
发生了什么以及为什么会发生
结果取决于您在程序崩溃时单击了哪个按钮。如果你的速度很慢,Windows 错误报告 (WER) 对话框将显示 "Debug" 和 "Close program"。如果您按下 "Close program" 按钮,程序将被操作系统终止,没有任何机会向控制台写入其他内容。
如果您足够快地点击 "Cancel" 按钮,那么 Windows 错误报告部分将被取消并且控制权返回到您的程序。然后它将 "Carrot" 写入控制台。
因此,这不是 .NET 问题,而是 Windows 如何对 exception dispatching 作出反应的问题。
如何控制它
要禁用 WER 对话框,您可以使用 WerAddExcludedApplication . To get rid of the Debug dialog, you can use SetErrorMode。
请熟悉使用这些方法的缺点。阅读Raymond Chen's comments on WerAddExcludedApplication and check whether SetThreadErrorMode可能会有所帮助。
您的代码可能如下所示:
using System;
using System.Runtime.InteropServices;
namespace ExceptionInCatch
{
class Program
{
[DllImport("wer.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern int WerAddExcludedApplication(String pwzExeName, bool bAllUsers);
[Flags]
public enum ErrorModes : uint
{
SYSTEM_DEFAULT = 0x0,
SEM_FAILCRITICALERRORS = 0x0001,
SEM_NOALIGNMENTFAULTEXCEPT = 0x0004,
SEM_NOGPFAULTERRORBOX = 0x0002,
SEM_NOOPENFILEERRORBOX = 0x8000,
SEM_NONE = SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX
}
[DllImport("kernel32.dll")]
static extern ErrorModes SetErrorMode(ErrorModes uMode);
public static void Main(string[] args)
{
var executableName = AppDomain.CurrentDomain.FriendlyName;
WerAddExcludedApplication(executableName, false);
SetErrorMode(ErrorModes.SEM_NONE);
try
{
throw new Exception("Apple");
}
catch (Exception ex)
{
throw new Exception("Banana");
}
finally
{
// This line will now execute
Console.WriteLine("Carrot");
}
}
}
}
以下是正确引发和处理异常的一些规则。我发现它们对我自己非常有用,并且喜欢 link 它们,因为当出现此类问题时,它们是一种资源。我在您的示例代码和您的问题中看到了许多经典错误:
http://blogs.msdn.com/b/ericlippert/archive/2008/09/10/vexing-exceptions.aspx
http://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET
Finally 块总是无误地执行。除非通过任务管理器终止整个进程,否则无法跳过它们。他们 运行 在 return 之后,在 catch 块中的另一个异常之后,在一切之后。异常处理只是一个代码流,主要由编译器强制执行。
我在 C# 中有一个简单的 try-catch-finally 块。据我了解,"finally" 块很有用,因为即使在 catch 块内抛出异常(除非有一些特殊的异常类型),它的代码也会执行。
但是,在下面的简单示例中,finally 块永远不会执行。 Visual Studio 说我的 catch 块中发生了未处理的异常,然后程序终止。我以为执行只会跳转到 finally 块。
如何保证finally块中的代码在catch块发生异常时执行?
public static void Main(string[] args)
{
try
{
throw new Exception("Apple");
}
catch (Exception ex)
{
throw new Exception("Banana");
}
finally
{
// This line never executes. Why?
Console.WriteLine("Carrot");
}
}
你抛出了第二个异常,没有捕获,第二个异常将不会继续代码..
Unhandled Exception: System.Exception: Banana
我建议你处理你的第一个异常,而不是抛出另一个。
static void Main(string[] args)
{
var x = 2;
try
{
if(x >1) throw new Exception("Apple");
}
catch (Exception ex)
{
x = 1;
}
finally
{
Console.WriteLine("Carrot");
}
}
如果您想了解更多关于异常处理的信息,RTFM:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/exception-handling
发生了什么以及为什么会发生
结果取决于您在程序崩溃时单击了哪个按钮。如果你的速度很慢,Windows 错误报告 (WER) 对话框将显示 "Debug" 和 "Close program"。如果您按下 "Close program" 按钮,程序将被操作系统终止,没有任何机会向控制台写入其他内容。
如果您足够快地点击 "Cancel" 按钮,那么 Windows 错误报告部分将被取消并且控制权返回到您的程序。然后它将 "Carrot" 写入控制台。
因此,这不是 .NET 问题,而是 Windows 如何对 exception dispatching 作出反应的问题。
如何控制它
要禁用 WER 对话框,您可以使用 WerAddExcludedApplication . To get rid of the Debug dialog, you can use SetErrorMode。
请熟悉使用这些方法的缺点。阅读Raymond Chen's comments on WerAddExcludedApplication and check whether SetThreadErrorMode可能会有所帮助。
您的代码可能如下所示:
using System;
using System.Runtime.InteropServices;
namespace ExceptionInCatch
{
class Program
{
[DllImport("wer.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern int WerAddExcludedApplication(String pwzExeName, bool bAllUsers);
[Flags]
public enum ErrorModes : uint
{
SYSTEM_DEFAULT = 0x0,
SEM_FAILCRITICALERRORS = 0x0001,
SEM_NOALIGNMENTFAULTEXCEPT = 0x0004,
SEM_NOGPFAULTERRORBOX = 0x0002,
SEM_NOOPENFILEERRORBOX = 0x8000,
SEM_NONE = SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX
}
[DllImport("kernel32.dll")]
static extern ErrorModes SetErrorMode(ErrorModes uMode);
public static void Main(string[] args)
{
var executableName = AppDomain.CurrentDomain.FriendlyName;
WerAddExcludedApplication(executableName, false);
SetErrorMode(ErrorModes.SEM_NONE);
try
{
throw new Exception("Apple");
}
catch (Exception ex)
{
throw new Exception("Banana");
}
finally
{
// This line will now execute
Console.WriteLine("Carrot");
}
}
}
}
以下是正确引发和处理异常的一些规则。我发现它们对我自己非常有用,并且喜欢 link 它们,因为当出现此类问题时,它们是一种资源。我在您的示例代码和您的问题中看到了许多经典错误:
http://blogs.msdn.com/b/ericlippert/archive/2008/09/10/vexing-exceptions.aspx http://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET
Finally 块总是无误地执行。除非通过任务管理器终止整个进程,否则无法跳过它们。他们 运行 在 return 之后,在 catch 块中的另一个异常之后,在一切之后。异常处理只是一个代码流,主要由编译器强制执行。