控制台应用程序以代码0(0x0)退出,尽管出现未处理的异常。

4
我正在编写一个非常简单的 .Net Framework (4.7) 控制台应用程序,故意抛出未处理的异常。但是程序仍然以代码 0 (0x0) 退出,这应该表示成功完成。
根据微软文档 此处 所述,默认值为 0(零),表示进程已成功完成。
我的问题是:我期望得到任何退出代码,但不是0。有人能解释一下我在这里错过了什么吗?
我的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {                    
            throw new Exception("Throw an exception");

            Console.WriteLine("Finishing program");
            Console.ReadLine();
        }
    }
}

输出窗口(Debug)消息:
发生了一个未处理的异常类型为'System.Exception'的异常在ConsoleApp2.exe中。
抛出一个异常。
程序“[7480]ConsoleApp2.exe”已以代码0(0x0)退出。
非常感谢。

1
你没有设置任何退出代码 - 既不通过 Environment.ExitCode,也不通过 static int Main(…) { return <your-exit-code>; } - 因此默认的退出代码适用。那么,框架如何知道每个特定异常的正确错误退出代码呢? - ckuri
1
首先,我模糊地记得只有控制台应用程序才能具有有意义的退出代码。窗口应用程序不需要这样的功能。其次,也许你必须自己设置退出代码。捕获异常,并在那里设置退出代码。 - Dialecticus
2个回答

8

出现这种情况是由于Visual Studio调试器中的一个bug!

调试器报告退出代码为0,但是调试器骗了你,实际上退出代码是非零的。

这个bug在这里讨论:https://github.com/dotnet/runtime/issues/35599#issuecomment-621954472

我引用其中的一段:

Visual Studio调试器有一个怪癖,即在Windows上,它会将因未处理异常而终止的程序的退出代码报告为0,但只有在从VS调试器运行程序时才会发生。如果你从命令行运行程序,就不会发生这种情况。

(请注意,他们称之为“怪癖”,而不是“bug”;这家公司的傲慢令人难以置信。)

尝试从批处理文件中运行程序并显示%errorlevel%,以查看真正的退出代码。

等等,还有更好的!

如果你使用批处理文件查看退出代码,你可能会惊奇地发现,它仍然不是你选择的值;相反,它是-532462766。

没错,退出代码是-532462766。

不是0,不是42,也不是-532462765,而是确切的-532462766。

什么鬼啊,对吧?

以32位十六进制表示,这个数字是0xE0434352,它是一个无名、基本未记录且缺乏文档说明的HRESULT,基本上代表“由于某些未指定的应用程序特定原因而导致的错误,我们不会告诉您具体是什么。”在这种情况下,应用程序特定的原因是未处理的DotNet异常导致进程崩溃。有传言称,这个HRESULT被称为“EXCEPTION_COMPLUS”或“CLR_EXCEPTION_V4”,尽管很难找到任何相关的文档。(另外,我可以声称最后3个十六进制数字拼成了“CCR”,这构成了对70年代一支著名摇滚乐队的参考,祝你好运反驳我的说法!)

等等,还有更棒的!

此时,你可能会尝试各种方式来强制Windows报告你自己选择的退出代码,而不是荒谬的-532462766退出代码。你可能会尝试:

  • 捕获异常并在重新引发异常之前设置ExitCode
  • 捕获异常并调用Environment.Exit()并传递你自己的退出代码;
  • 注册一个AppDomain未经处理的异常处理程序,并在其中设置ExitCode
  • 在AppDomain未经处理的异常处理程序中注册并从处理程序内部调用Environment.Exit(),并使用你自己的退出代码;

等等。

这一切都将是浪费时间。没有任何作用。在未处理的异常情况下,Microsoft已经非常努力地确保DotNet进程将以退出代码-532462766终止,除了退出代码-532462766之外什么也不会发生。

-532462766对于每个人来说应该足够了。


-4
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Program
    {
        bool continueThrow = true;
        static int Main(string[] args)
        {   
             try{
                 //doThings
             }catch(Exception ex){
                 //log the exception;
                 Environment.ExitCode = number;
                 if(continueThrow){
                      throw;
                 }
            } 
            Console.WriteLine("Finishing program");
            Console.ReadLine();

            return 0;
        }
    }
}

3
这完全是错误的。如果出现未处理的异常,退出代码将不为零。OP的问题源于Mike Nakis所述的错误。 - Dominik
请参阅解释完全基于代码的答案。您的答案最好附带解释。 - Gerhard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接