目录
前言
控制台应用 Console,在我们开发中用处很多。小到一个简单的功能测试,或一组不需要复杂 UI 的工具类应用,大到后端的服务,都会用到 Console。
在这里面,命令行应用 Cli,又是非常典型的一个应用类型。
命令行应用,通常概念上需要我们输入一定参数,根据参数的不同,选择不同的程序流程或方法来执行。
举个简单的例子:
% python3
Python 3.9.0 (default, Nov 13 2020, 12:12:14)
[Clang 12.0.0 (clang-1200.0.32.21)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import OS
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'OS'
>>> import os
>>> print("Hello WangPlus")
Hello WangPlus
>>> exit()
不需要管 python3 是什么,这不重要。
我们能看到,当进入一个命令行时,一般首先会有简单的功能介绍,然后是一个提示符,在这里是 >>>。然后可以输入命令和参数,如果输入正确,会有错误提示。如果输入正确,会有适当的输出。
通常,如果想实现这样的效果,我们需要一个大的循环,来解析和响应输入的命令和参数,然后进行对应的处理。
事实上,在做这样一个应用时,会有很大的精力来处理这个循环。不相信的话,可以自己试着写一写。
今天给大家介绍的,是一个库,Nuget 上的库,也是我最近无意中发现的,但给了我很大的惊喜。事实上,我自己在写应用时,如果有可能,我会优先采用 Console 或 Cli 的方式来写,轻量、快速,不用处理太多 UI 方面的工作。
这个库叫 CommandLineTool。
下面进入正题,我从头介绍一下这个库的使用。
创建项目
先来创建项目。*惯,用命令行创建:
% dotnet new console -o demo -f net5.0
这儿需要注意一下,这个库目前支持到 Dotnet Core 5.0,所以我们就用 5.0 了。
然后,引入 CommandLineTool:
% dotnet add package CommandLineTool
就这样,工程就算是建完了。
实现功能
这个库最简单的地方,是实现起来非常简单。
第一步,先建一个类
这个类,就是我们要实现 Cli 命令行功能的类 TestCLI:
[App("Demo")]
public class TestCLI
{
}
类是空的,先不管它。
第二步,在 Program.cs 里加入这个类
class Program
{
static void Main(string[] args)
{
Cli cli = new Cli(typeof(TestCLI))
{
Introduction = "这是一个 Demo 应用",
PromptText = "WangPlus",
};
cli.SetCancellationKeys(new() { "exit" });
cli.Start();
}
}
看一个加入的内容:
Introduction - 这个 Cli 的说明,提示一下这个程序的功能,随便写;
PromptText - 这个是提示符的内容,类似于最上面例子的 >>>;
下面这一句cli.SetCancellationKeys(new() { "exit" });
,是定义了退出的命令。也就是说,在提示符后输入 exit,应用就退出了。
跑一下这个应用:
% dotnet demo.dll
这是一个 Demo 应用
WangPlus > ?
'?' was not matched. Did you mean '-h'?
Unrecognized command or argument '?'
demo
Demo
Usage:
demo [options]
Options:
--version Show version information
-?, -h, --help Show help and usage information
WangPlus >exit
Terminating console...
哇哈哈,一个简单的 Cli 架子搭出来了。
第三步,开始写命令处理
命令处理放在 TestCLI.cs 中。
[App("Demo")]
public class TestCLI
{
[Command("hello", "就是打个招呼")]
public static void Hello([ParamArgument()] string name)
{
Console.WriteLine($"Hello {name}");
}
}
方法还是我们非常熟悉的一个普通方法,并没有什么特别的。
再跑一下:
WangPlus >hello
Required argument missing for command: hello
hello
就是打个招呼
Usage:
demo [options] hello <name>
Arguments:
<name>
Options:
-?, -h, --help Show help and usage information
WangPlus >hello wang
Hello wang
出来效果了。
重点看一下代码里的几个部分:
属性 Command,里面两个参数,第一个参数就是我们要实现的命令,第二个参数是命令的说明。
方法里,[ParamArgument()] 表示后面跟的参数来自于输入的命令的参数。
下面还有几种形式:
//多个参数
[Command("multiinput", "多个参数")]
public static void MultiInput([ParamArgument()] List<string> names) {}
//多个文件
[Command("multifile", "多个文件")]
public static void MultiFile([ParamArgument()] List<FileInfo> files) {}
//额外的参数
[Command("withpara", "额外参数")]
public static void WithPara([ParamArgument()] string names, [ParamOption("-a")] string op1) {}
重点说一下额外参数的方式。
有时候,我们可能需要下面的方式来处理命令:
% demo -a a-value -b b-value command
这个方式,就是来解决这样的问题的。
有没有 Get 到爽点?
本文有配套代码,在 https://github.com/humornif/Demo-Code/tree/master/0053/demo