我在C#中有一个简单的try-catch-finally块。据我所知,“finally”块很有用,因为即使在catch块中抛出异常,它的代码也会执行(除非有一些特殊的异常类型)。
但是,在下面的简单示例中,finally块永远不会执行。 Visual Studio说我的catch块中发生了未处理的异常,然后程序终止。我认为执行只会跳转到finally块。
即使catch块中发生异常,如何确保finally块中的代码执行?
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");
}
}
答案 0 :(得分:1)
结果取决于程序崩溃时单击的按钮。如果您变慢,Windows错误报告(WER)对话框将显示" Debug"和"关闭程序"。如果按"关闭程序"按钮,程序由operationg系统终止,没有任何机会向控制台写入其他内容。
如果你足够快,可以点击"取消"按钮,然后Windows错误报告部分将被取消,控制权将返回到您的程序。然后它将编写" Carrot"到控制台。
因此,这不是.NET问题,而是Windows如何对exception dispatching做出反应的问题。
要禁用WER对话框,您可以使用WerAddExcludedApplication 。要删除“调试”对话框,可以使用SetErrorMode。
请熟悉使用这些方法的不足之处。阅读Raymond Chen's comments on WerAddExcludedApplication 并检查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");
}
}
}
}
答案 1 :(得分:0)
以下是适当的异常提升和处理的一些规则。我发现这对我自己非常有用,并且当这些问题出现时,喜欢将它们作为资源链接起来。我在你的示例代码中看到了许多经典错误,确实存在于你的问题中:
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
最后,块总是在没有失败的情况下执行。如果没有通过任务管理器杀死整个过程,就无法跳过它们。它们在返回之后运行,在一个catch块中的另一个异常之后运行。异常处理只是一个主要由编译器强制执行的代码流。
答案 2 :(得分:-1)
你引发第二个异常,没有捕获,第二个异常将不会继续代码..
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");
}
}
如果您想了解有关异常处理的更多信息,请转发:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/exception-handling