实现 C# 控制台应用程序的正确方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/836477/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 03:33:54  来源:igfitidea点击:

Correct way to implement C# console application?

c#command-lineconsolearguments

提问by James

What is the correct way to implement and architect a command line tool as a C# console application?

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

Concerns to address include proper parsing of command line variables, and the proper way to output text. While Console.WriteLine() is the most obvious choice for output, what are the circumstances in which one should instead opt to write to the standard error stream, .Error, .SetErrorStream, etc?

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

What is the proper way for the application to exit while returning a proper return code to the calling command?

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

How should the the CancelKeyPress event be implemented to interrupt the program? Is it only for use when an asynchronous operation is occurring on a separate thread?

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

Is there a concise guide to command line tool programming in C#, or even better an open source project or template which I could use to properly implement a relatively simple tool?

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

采纳答案by Joe

Error messages should be written to stderr aka Console.Error, and normal output to stdout aka Console.Out. This is particularly important for "filter" type console apps whose output (stdout) can be piped to another process, e.g. in a batch file.

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

Generally if you encounter an error, write an error message to Console.Error and return a non-zero result. Or if it's an exception, just don't bother handling it.

通常,如果遇到错误,将错误消息写入 Console.Error 并返回非零结果。或者如果它是一个例外,就不要费心去处理它。

To return a result code, you can either pass it as an argument to Environment.Exit, set the Environment.ExitCode property, or return a non-zero value from main.

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

For simple console apps I would:

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

  • have a helper class to parse the command line.

  • have a facade class that provides a testable API for the functionality implemented by your command line tool. Like most .NET APIs, this would normally throw an exception if an error occurs.

  • the main program simply uses the helper to parse the command line and calls the API passing the arguments passed from the command line. It optionally catches exceptions thrown from the API, logs them, writes a user-oriented error message to Console.Error and sets a non-zero return code.

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

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

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

But I wouln't consider this to be the one true way: there isn't really such a thing which is why you're unlikely to find the book you're looking for.

但我不会认为这是唯一正确的方法:实际上并不存在这样的事情,这就是为什么您不太可能找到您要找的书的原因。

回答by Adam Robinson

As for command line arguments, you'll find various schemes, but I've always been a fan of

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

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

As for the return code, you can change the signature of your Main()function to return an intrather than void. This will allow you to return a code to the calling process, if necessary.

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

As for the error stream, I've never personally used it, and I don't think that it should come at the expense of outputting error information in the standard output stream. It's probably better used for specific error debugging information.

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

回答by Cecil Has a Name

As to how to implement command parsing, I've succesfully used reflection and delegates before. They way it works is to decorate command methods with a special attribute you make yourself that states the method should be user-invokable, either through the method's name or a string specified in the attribute, i.e.:

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

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

On program startup you can scan a class for such methods, and store delegates that target them in a dictionary where the keys are the commands. This makes it easy to parse commands based on looking up the first word in a dictionary (amortized O(1) ) and easily extensible and maintanable for the future, as new commands are added simply adding separate methods.

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

回答by Todd

For command-line handling, check out Mono.GetOptions. It makes it easy to populate variables from short (-f style) and long (--file style) command line options.

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

回答by Josh

I've opted to write a number of console utility apps as windows form applications instead of console apps. Generally, I add a timer to delay initial start and just add a cancel button with a progress meter--thus allowing a more intuitive cancel option. You can still output to the console that way too.

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