如何在特定异常时终止 .NET 应用程序 - 可能没有堆栈展开?

How to terminate .NET application on a specific exception - possibly without stack unwinding?

我有一个由 C# 和 C++ 代码组成的 .NET 应用程序(服务)。

"Crashes"(即System.AccessViolationExceptionCorrupted State Exceptions)在C++代码中会被("non-")正确处理,它们会直接导致我的AppDomain.CurrentDomain.UnhandledException 处理程序(记录日志),然后应用程序将终止,如果这样配置(它是),则写入一个 WER 转储文件。

对于这个应用程序,我确定 System.NullReferenceException 始终是一个错误,尤其是 因为一些 C++/CLI 访问冲突错误会报告这个错误而不是 AV .

有没有办法让 .NET 在异常边界上捕获 NullReferenceException(在这种情况下是我的 OnTimer 回调)而是直接终止应用程序,没有展开堆栈,基本上"jumping"直接到AppDomain.CurrentDomain.UnhandledException?

你可以:

AppDomain.CurrentDomain.FirstChanceException += CurrentDomain_FirstChanceException;

然后

static void CurrentDomain_FirstChanceException(object sender, FirstChanceExceptionEventArgs e)
{
    if (e.Exception is NullReferenceException)
    {
        Environment.FailFast("FailFast", e.Exception);
    }
}

Environment.FailFast:

Immediately terminates a process after writing a message to the Windows Application event log, and then includes the message in error reporting to Microsoft.

This method terminates a process without running any active try/finally blocks or finalizers.

很明显,在 CurrentDomain_FirstChanceException 中,您可以复制您在 UnhandledException 中可能拥有的日志记录代码(或者有一个由两者调用的通用方法)

FirstChanceException 实际上是一个 "simple" 全局异常过滤器这一事实让我走上了轨道(是否是 "right" 轨道还有待观察):

我们在 CLI 中已经有了异常过滤器

如果有幸在 C# 6 中工作,那就很简单:

        try
        {
            throw new NullReferenceException("No, Really");
        }
        catch(Exception ex) when (FilterExType(ex))
        {
            Console.WriteLine($"2: Caught 'any' exception: {ex}");
        }

    static bool FilterExType(Exception ex)
    {
        if (ex is NullReferenceException)
        {
            Environment.FailFast("BOOM from C#!", ex);
        }
        // always handle if we return
        return true;
    }

对于我们这些坚持使用早期版本的人(比如我),我们可以通过委托/lambda 通过 VB.NET 路由过滤:

        try {
            VbFilterLib.FilteredRunner.RunFiltered(() =>
            {
                throw new NullReferenceException("Via VB.NET");
            });
        } 
        catch (Exception ex)
        {
            Console.WriteLine("1: Caught 'any' exception: {0}", ex");
        }

与 VB 一样(请耐心等待,VB.NET 与我精通的语言 相去甚远

Public Class FilteredRunner
    Delegate Sub VoidCode()

    Private Shared Function FilterAction(x As Exception) As Boolean
        If TypeOf x Is NullReferenceException Then
            Environment.FailFast("Abort program! Investigate Bug via crash dump!", x)
        End If
        ' Never handle here:'
        Return False
    End Function

    Public Shared Sub RunFiltered(code As VoidCode)
        Try
            code.Invoke()
        Catch ex As Exception When FilterAction(ex)
            Throw New InvalidProgramException("Unreachable!", ex)
        End Try
    End Sub

End Class

显然,要使其正常工作,您需要进行更多配置,但这似乎正是我想要的。 :-)