22

将命令行工具实现和架构为 C# 控制台应用程序的正确方法是什么?

需要解决的问题包括正确解析命令行变量,以及输出文本的正确方法。虽然 Console.WriteLine() 是最明显的输出选择,但在什么情况下应该选择写入标准错误流、.Error、.SetErrorStream 等?

应用程序在向调用命令返回正确的返回码时退出的正确方法是什么?

应该如何实现CancelKeyPress事件来中断程序?是否仅在单独线程上发生异步操作时使用?

是否有 C# 中命令行工具编程的简明指南,或者更好的开源项目或模板,我可以使用它来正确实现相对简单的工具?

4

5 回答 5

27

错误消息应写入 stderr aka Console.Error,并将正常输出写入 stdout aka Console.Out。这对于“过滤器”类型的控制台应用程序尤其重要,这些应用程序的输出(标准输出)可以通过管道传输到另一个进程,例如在批处理文件中。

一般如果遇到错误,将错误信息写入 Console.Error 并返回非零结果。或者,如果这是一个例外,请不要费心处理它。

要返回结果代码,您可以将其作为参数传递给 Environment.Exit,设置 Environment.ExitCode 属性,或者从 main 返回一个非零值。

对于简单的控制台应用程序,我会:

  • 有一个帮助类来解析命令行。

  • 有一个外观类,它为您的命令行工具实现的功能提供可测试的 API。与大多数 .NET API 一样,如果发生错误,这通常会引发异常。

  • 主程序只是使用帮助程序来解析命令行并调用 API 传递从命令行传递的参数。它可以选择捕获从 API 抛出的异常,记录它们,将面向用户的错误消息写入 Console.Error 并设置非零返回码。

但我不认为这是一种真正的方式:实际上并不存在这样的事情,这就是为什么你不太可能找到你要找的书的原因。

于 2009-05-07T19:35:49.300 回答
5

至于如何实现命令解析,我之前已经成功使用过反射和委托。它们的工作方式是使用您自己创建的特殊属性来装饰命令方法,该属性声明该方法应该是用户可调用的,可以通过方法的名称或属性中指定的字符串,即:

[Command("quit")]
public void QuitApp()
{
    ...
}

在程序启动时,您可以扫描类中的此类方法,并将针对它们的委托存储在字典中,其中键是命令。这使得基于在字典中查找第一个单词(摊销 O(1) )来解析命令变得容易,并且在未来很容易扩展和维护,因为只需添加单独的方法即可添加新命令。

于 2009-05-07T19:39:24.533 回答
2

至于命令行参数,你会发现各种方案,但我一直很喜欢

app.exe "self-explanatory arg" /noArgumentSwitch /argumentSwitch="argument"

至于返回码,您可以将Main()函数的签名更改为返回int而不是void. 如有必要,这将允许您将代码返回给调用进程。

至于错误流,我从来没有亲自使用过,我认为不应该以在标准输出流中输出错误信息为代价。它可能更适合用于特定的错误调试信息。

于 2009-05-07T19:19:52.300 回答
2

对于命令行处理,请查看 Mono.GetOptions。它可以轻松地从短(-f 样式)和长(--file 样式)命令行选项填充变量。

于 2009-05-07T19:40:58.570 回答
0

我选择将许多控制台实用程序应用程序编写为 Windows 窗体应用程序而不是控制台应用程序。通常,我会添加一个计时器来延迟初始启动,并添加一个带有进度表的取消按钮——从而允许更直观的取消选项。您仍然可以通过这种方式输出到控制台。

于 2009-05-07T19:54:24.370 回答