在.NET中,如何指定控制台应用程序的退出代码?

563

我有一个简单的.NET控制台应用程序,它只是一个较大应用程序的测试部分。我想指定控制台应用程序的“退出代码”。我该如何做?

14个回答

710

有三种选择:

  • 如果声明你的Main方法返回int,则可以从Main中返回它。
  • 你可以调用Environment.Exit(code)
  • 你可以使用属性设置退出代码Environment.ExitCode = -1;。如果没有其他选项设置返回代码或使用上述其他选项,则将使用此选项)。

根据你的应用程序(控制台、服务、Web 应用程序等),可使用不同的方法。


17
如果你想知道为什么这在你的情况下不起作用,请确保你的项目被编译为“控制台应用程序”,而不是“Windows 应用程序”。 - Marcel Gosselin
11
如果我有一个WinForms应用程序,并且希望通过某些参数使其像控制台应用程序一样运行,该怎么办? - sebagomez
5
你也可以将主程序声明为整型(将void替换为int),例如使用"return -1;"语句来退出主程序。这种方法比Environment.Exit()更具可移植性(因为它依赖于环境)。 - werner
15
按照惯例,退出码为 0 表示成功,非零表示失败。return; 表示通过退出码 0 成功,而 return -1; 则表示失败。 - allonhadaya
7
您可以使用属性设置退出代码:Environment.ExitCode = -1; - t3b4n
显示剩余5条评论

307

除了回答覆盖返回int之外,还有一个关于理智的请求。请,请使用枚举定义您的退出代码,如适用,则使用标志。这将使调试和维护变得更加容易(并且作为奖励,您可以轻松地在帮助屏幕上打印出退出代码 - 您肯定有一个这样的屏幕,对吧?)。

enum ExitCode : int {
  Success = 0,
  InvalidLogin = 1,
  InvalidFilename = 2,
  UnknownError = 10
}

int Main(string[] args) {
   return (int)ExitCode.Success;
}

57
请注意,对于“成功”的值为“0”,这并非偶然,而实际上是该情况的“标准”值。 - Christian.K
2
我知道0代表成功的标准。 除此之外,是否有其他退出代码的约定,还是完全自由?(我假设这些是运行计划任务后返回的相同数字)。 - AndyM
22
您说0是成功的标准值,但是当将0/1转换为布尔值时,0表示假,1表示真!更准确的说法可能是,退出代码为0表示“没有错误”,而不是“成功”,因为退出代码是一个ErrorResult而不仅仅是一个Result。 - Mark Shapiro
11
完整的微软规范清单请参阅http://msdn.microsoft.com/zh-cn/library/windows/desktop/ms681382(v=vs.85).aspx。有人在下面的评论中制作了一个大型常量列表,并在switch case语句中使用它。 - nawfal
6
@MarkShapiro,我猜“0 = Success”的原因是只需要一个成功代码,但需要许多错误代码,因此在计算机整数中,0 没有正负号,可以用来唯一标识成功。 - Sebastian
显示剩余3条评论

58
有三种方法可以用于从控制台应用程序返回退出代码。
  1. 修改应用程序中的Main方法,使其返回int而不是void(在VB.NET中返回一个Integer而不是Sub),然后从该方法返回退出代码。
  2. 设置Environment.ExitCode属性为退出代码。请注意,方法1优先 - 如果Main方法返回除void之外的任何内容(在VB.Net中是一个Sub),则此属性的值将被忽略。
  3. 将退出代码传递给Environment.Exit方法。与其他两种方法不同,这将立即终止进程。
一个重要的标准是,0表示“成功”。
在相关主题上,考虑使用枚举定义应用程序将返回的退出代码。 FlagsAttribute将允许您返回组合代码。
此外,请确保将应用程序编译为“控制台应用程序”。

2
这提出了一个有趣的观点。设置 Environment.ExitCode 不会立即关闭程序,但是 Environment.Exit 方法会立即关闭程序。 - PsychoData
2
退出代码也适用于Windows应用程序。如果该应用程序是通过C#中的Process对象启动的,您可以要求该对象WaitForExit(),然后从中请求退出代码。 - Nyerguds

44

如果您要使用David提出的方法,您还应该查看[Flags]属性。

这样可以让您在枚举类型上执行按位操作。

[Flags]
enum ExitCodes : int
{
  Success = 0,
  SignToolNotInPath = 1,
  AssemblyDirectoryBad = 2,
  PFXFilePathBad = 4,
  PasswordMissing = 8,
  SignFailed = 16,
  UnknownError = 32
}

那么

(ExitCodes.SignFailed | ExitCodes.UnknownError)

结果将为16 + 32. :)


4
这意味着程序会说“您的密码不正确”,然后继续尝试签署它正在签署的内容,只有在签署失败时才停止。你应该在失败后返回;除此以外的任何情况都是警告,程序仍应返回0。 - Pete Kirkham
3
鲜为人知的是,[Flags] 并不会启用或禁用按位运算。它只是重写 ToString 方法,以便输出表示按位标志的内容。有或没有 [Flags],您仍然可以进行按位运算。 - Steven Berkovitz
4
@Steven,知道这一点很好,但我仍然建议用该属性装饰旨在“标记使用”的枚举,如果没有其他事情的话,它至少传达了意图。 - MarioDS

30

26
int code = 2;
Environment.Exit( code );

19
为什么你不直接写成“Environment.Exit( 2 );”呢? - Blorgbeard
65
给一个无意义的变量命名加上一个神奇数字并不能使它变得不那么神奇。 - Blorgbeard
3
@Blorgbeard - 你在两个评论之间已经过去了七年。这有点史诗般的感觉。 :-D - Tornseglare
3
@Tornseglare,我期待着这方面的更新。预计会在几个月内到来 :) - El Ronnoco
@el-ronnoco - 你和我一样失望吗? - InbetweenWeekends

16

只需从主函数返回适当的代码。

int Main(string[] args)
{
    return 0; // Or exit code of your choice
}

11

如果您的main方法具有void返回类型,请使用ExitCode。否则,您需要通过您返回的值来“设置”它。

来自Environment.ExitCode属性

如果Main方法返回void,则可以使用该属性设置将返回到调用环境的退出代码。如果Main不返回void,则该属性将被忽略。此属性的初始值为零。


8

枚举选项非常出色。然而,可以通过像下面这样将数字相乘来改进:

enum ExitCodes : int
{
  Success = 0,
  SignToolNotInPath = 1,
  AssemblyDirectoryBad = 2,
  PFXFilePathBad = 4,
  PasswordMissing = 8,
  SignFailed = 16,
  UnknownError = 32
}

在出现多个错误的情况下,将具体的错误编号相加,可以得到一个唯一的数字,代表检测到的错误组合。
例如,错误级别为6只能由4和2两种错误组成,12只能由4和8两种错误组成,14只能由2、4和8三种错误组成等。

3
如果你在遇到错误后费心检查进一步的错误,那就好了。然而,大多数应用程序并没有这样做。 - Nyerguds

8

2
你提到的关于C# 6的第一个观点能够被证实吗?我在网上找不到任何相关信息。在之前的编译器中,Main函数的返回值会附加到进程的退出代码上(至少是这样的),为什么他们要改变这个呢? - Arman
纯属个人经验,但我在自己的库中遇到了这个问题,即仅从Main()返回我的结果/错误代码并没有设置由调用应用程序看到的Process.ExitCode - Marcus Mangelsdorf
1
MSDN认为int Main仍然可以作为Environment.ExitCode的替代选项。 - Arman
1
我有一个运行多个线程的应用程序。在某些情况下,我需要通过Thread.Abort()来清除一些线程,然后退出应用程序。在这些情况下,int Main(){...thread.Abort(); ... return 0;}不会导致进程退出代码为0:进程退出代码为-1。在某些情况下,微软已经决定使用主线程的返回值来设置进程的退出代码的约定对他们来说不够好。公平地说,这可能是一个时间问题:线程中止可能会在游戏的最后阶段设置退出代码。 - David I. McIntosh

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