Dotnet Core 優(yōu)雅的命令行實(shí)現(xiàn)
本文轉(zhuǎn)載自微信公眾號(hào)「老王Plus」,作者老王Plus的老王。轉(zhuǎn)載本文請(qǐng)聯(lián)系老王Plus公眾號(hào)。
前言
控制臺(tái)應(yīng)用 Console,在我們開發(fā)中用處很多。小到一個(gè)簡(jiǎn)單的功能測(cè)試,或一組不需要復(fù)雜 UI 的工具類應(yīng)用,大到后端的服務(wù),都會(huì)用到 Console。
在這里面,命令行應(yīng)用 Cli,又是非常典型的一個(gè)應(yīng)用類型。
命令行應(yīng)用,通常概念上需要我們輸入一定參數(shù),根據(jù)參數(shù)的不同,選擇不同的程序流程或方法來執(zhí)行。
舉個(gè)簡(jiǎn)單的例子:
- % 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 是什么,這不重要。
我們能看到,當(dāng)進(jìn)入一個(gè)命令行時(shí),一般首先會(huì)有簡(jiǎn)單的功能介紹,然后是一個(gè)提示符,在這里是 >>>。然后可以輸入命令和參數(shù),如果輸入正確,會(huì)有錯(cuò)誤提示。如果輸入正確,會(huì)有適當(dāng)?shù)妮敵觥?/p>
通常,如果想實(shí)現(xiàn)這樣的效果,我們需要一個(gè)大的循環(huán),來解析和響應(yīng)輸入的命令和參數(shù),然后進(jìn)行對(duì)應(yīng)的處理。
事實(shí)上,在做這樣一個(gè)應(yīng)用時(shí),會(huì)有很大的精力來處理這個(gè)循環(huán)。不相信的話,可以自己試著寫一寫。
今天給大家介紹的,是一個(gè)庫,Nuget 上的庫,也是我最近無意中發(fā)現(xiàn)的,但給了我很大的驚喜。事實(shí)上,我自己在寫應(yīng)用時(shí),如果有可能,我會(huì)優(yōu)先采用 Console 或 Cli 的方式來寫,輕量、快速,不用處理太多 UI 方面的工作。
這個(gè)庫叫 CommandLineTool。
下面進(jìn)入正題,我從頭介紹一下這個(gè)庫的使用。
創(chuàng)建項(xiàng)目
先來創(chuàng)建項(xiàng)目。老習(xí)慣,用命令行創(chuàng)建:
- % dotnet new console -o demo -f net5.0
這兒需要注意一下,這個(gè)庫目前支持到 Dotnet Core 5.0,所以我們就用 5.0 了。
然后,引入 CommandLineTool:
- % dotnet add package CommandLineTool
就這樣,工程就算是建完了。
實(shí)現(xiàn)功能
這個(gè)庫最簡(jiǎn)單的地方,是實(shí)現(xiàn)起來非常簡(jiǎn)單。
第一步,先建一個(gè)類
這個(gè)類,就是我們要實(shí)現(xiàn) Cli 命令行功能的類 TestCLI:
- [App("Demo")]
- public class TestCLI
- {
- }
類是空的,先不管它。
第二步,在 Program.cs 里加入這個(gè)類
- class Program
- {
- static void Main(string[] args)
- {
- Cli cli = new Cli(typeof(TestCLI))
- {
- Introduction = "這是一個(gè) Demo 應(yīng)用",
- PromptText = "WangPlus",
- };
- cli.SetCancellationKeys(new() { "exit" });
- cli.Start();
- }
- }
看一個(gè)加入的內(nèi)容:
Introduction - 這個(gè) Cli 的說明,提示一下這個(gè)程序的功能,隨便寫;
PromptText - 這個(gè)是提示符的內(nèi)容,類似于最上面例子的 >>>;
下面這一句cli.SetCancellationKeys(new() { "exit" });,是定義了退出的命令。也就是說,在提示符后輸入 exit,應(yīng)用就退出了。
跑一下這個(gè)應(yīng)用:
- % dotnet demo.dll
- 這是一個(gè) Demo 應(yīng)用
- 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...
哇哈哈,一個(gè)簡(jiǎn)單的 Cli 架子搭出來了。
第三步,開始寫命令處理
命令處理放在 TestCLI.cs 中。
- [App("Demo")]
- public class TestCLI
- {
- [Command("hello", "就是打個(gè)招呼")]
- public static void Hello([ParamArgument()] string name)
- {
- Console.WriteLine($"Hello {name}");
- }
- }
方法還是我們非常熟悉的一個(gè)普通方法,并沒有什么特別的。
再跑一下:
- WangPlus >hello
- Required argument missing for command: hello
- hello
- 就是打個(gè)招呼
- Usage:
- demo [options] hello <name>
- Arguments:
- <name>
- Options:
- -?, -h, --help Show help and usage information
- WangPlus >hello wang
- Hello wang
出來效果了。
重點(diǎn)看一下代碼里的幾個(gè)部分:
屬性 Command,里面兩個(gè)參數(shù),第一個(gè)參數(shù)就是我們要實(shí)現(xiàn)的命令,第二個(gè)參數(shù)是命令的說明。
方法里,[ParamArgument()] 表示后面跟的參數(shù)來自于輸入的命令的參數(shù)。
下面還有幾種形式:
- //多個(gè)參數(shù)
- [Command("multiinput", "多個(gè)參數(shù)")]
- public static void MultiInput([ParamArgument()] List<string> names) {}
- //多個(gè)文件
- [Command("multifile", "多個(gè)文件")]
- public static void MultiFile([ParamArgument()] List<FileInfo> files) {}
- //額外的參數(shù)
- [Command("withpara", "額外參數(shù)")]
- public static void WithPara([ParamArgument()] string names, [ParamOption("-a")] string op1) {}
重點(diǎn)說一下額外參數(shù)的方式。
有時(shí)候,我們可能需要下面的方式來處理命令:
- % demo -a a-value -b b-value command
這個(gè)方式,就是來解決這樣的問題的。
有沒有 Get 到爽點(diǎn)?
本文有配套代碼,在 https://github.com/humornif/Demo-Code/tree/master/0053/demo