在「主控台應用程式」(指令視窗應用程式、Console Application) 中如果要方便讓其他使用者或程式使用,基本上都會需要讀取傳入參數,而傳入參數通常會以 string[] args 的方式存在。
但主要的程式邏輯都處理不完了,還要判斷哪個參數是哪個、可能不一致的參數順序、可選參數和必要參數等等都要從一個陣列中整理和判斷,實在有夠麻煩...
還好這些已經有網路上的大神處理過並做好套件讓我們可以方便使用了。 今天要介紹的就是筆者最常使用的幫助解析和處理參數的套件 — CommandLineUtils
註: CommandLineUtils 主要可以區分為兩種撰寫風格,分別是屬性(Attributes) 和建造者模式(Builder Pattern),筆者比較習慣使用屬性的方式,並且覺得屬性也比較好理解,下面的示範都會是使用這種方式。
在 Program.cs 輸入以下程式碼:
註: 在 .NET 6 以後使用頂級語句,Program.cs 一開啟會只有兩行程式碼,直接把上面的程式貼上並取代 Program.cs 裡的程式碼即可。
使用 CommandLineApplication.Execute 時(第 5 行)程式的進入點會變成 OnExecute 或 OnExecuteAsync 方法(第 7~9 行), 如果沒有 OnExecute 或 OnExecuteAsync 的話會拋出下面的錯誤:
所以遇到這個錯誤記得檢查是不是少了 OnExecute 或 OnExecuteAsync 方法
如果沒有找到的話可以先在 .csproj 檔案的同層級路徑輸入下面的指令:
每次更改要測試都要記得重新 build 一次,不然執行檔不會更新
預設可以使用減號加變數首字母小寫(-u)或是兩個減號加上變數小寫全名使用參數。(假設變數名稱是 User,就是 --user)
如果有多個大寫,例如上面的 UserId,則以減號區隔 (--user-id)
使用方式:
也可以自訂參數名稱
原本的 -u 和 --user-id 就會失效,變成新的 -i 和 --Id
範例輸出:
預設為 false,如果使用 -v 或是 --verbose 則會變成 true , -v 和 --verbose 後面不能帶入參數
如果使用 public bool Verbose { get; } = true; 則不管有沒有帶入參數都是 True
如果想要預設值為 true,並且可以更改, 唯一的解法就是使用 CommandOptionType.SingleValue ,只是這樣後方就一定要帶入參數
範例輸出:
參考資料:
CommandLineUtils
但主要的程式邏輯都處理不完了,還要判斷哪個參數是哪個、可能不一致的參數順序、可選參數和必要參數等等都要從一個陣列中整理和判斷,實在有夠麻煩...
還好這些已經有網路上的大神處理過並做好套件讓我們可以方便使用了。 今天要介紹的就是筆者最常使用的幫助解析和處理參數的套件 — CommandLineUtils
註: CommandLineUtils 主要可以區分為兩種撰寫風格,分別是屬性(Attributes) 和建造者模式(Builder Pattern),筆者比較習慣使用屬性的方式,並且覺得屬性也比較好理解,下面的示範都會是使用這種方式。
安裝 CommandLineUtils
使用 NuGet 安裝 CommandLineUtils 套件,或是使用 .NET CLI 指令安裝:
dotnet add package McMaster.Extensions.CommandLineUtils
在 Program.cs 輸入以下程式碼:
using McMaster.Extensions.CommandLineUtils;
class Program
{
static void Main(string[] args) => CommandLineApplication.Execute<Program>(args);
private void OnExecute()
{
Console.WriteLine("Hello World!");
}
}
註: 在 .NET 6 以後使用頂級語句,Program.cs 一開啟會只有兩行程式碼,直接把上面的程式貼上並取代 Program.cs 裡的程式碼即可。
使用 CommandLineApplication.Execute 時(第 5 行)程式的進入點會變成 OnExecute 或 OnExecuteAsync 方法(第 7~9 行), 如果沒有 OnExecute 或 OnExecuteAsync 的話會拋出下面的錯誤:
Unhandled exception. System.InvalidOperationException: No method named 'OnExecute' or 'OnExecuteAsync' could be found.
at McMaster.Extensions.CommandLineUtils.Conventions.ExecuteMethodConvention.OnExecute(ConventionContext context, CancellationToken cancellationToken)
at McMaster.Extensions.CommandLineUtils.Conventions.ExecuteMethodConvention.<>c__DisplayClass0_0.<<Apply>b__0>d.MoveNext()
--- End of stack trace from previous location ---
at McMaster.Extensions.CommandLineUtils.CommandLineApplication.ExecuteAsync(String[] args, CancellationToken cancellationToken)
at McMaster.Extensions.CommandLineUtils.CommandLineApplication.ExecuteAsync[TApp](CommandLineContext context, CancellationToken cancellationToken)
at McMaster.Extensions.CommandLineUtils.CommandLineApplication.Execute[TApp](CommandLineContext context)
at McMaster.Extensions.CommandLineUtils.CommandLineApplication.Execute[TApp](IConsole console, String[] args)
at McMaster.Extensions.CommandLineUtils.CommandLineApplication.Execute[TApp](String[] args)
at ConsoleAppCommandLineUtilsTest.Program.Main(String[] args) in C:\Users\ruyut\ConsoleAppCommandLineUtilsTest\ConsoleAppCommandLineUtilsTest\Program.cs:line 7
Process finished with exit code -532,462,766.
所以遇到這個錯誤記得檢查是不是少了 OnExecute 或 OnExecuteAsync 方法
使用方式
在本文中我們會需要多次呼叫 exe 檔案並帶入參數,為了測試方便,筆者會開啟指令視窗呼叫 exe 檔案。exe 檔案的預設目錄在專案下的 /bin/Debug/net6.0 資料夾內(最後一層是 .NET 版本號碼),例如專案名稱為 ConsoleAppCommandLineUtilsTest ,執行檔的位置就是:
ConsoleAppCommandLineUtilsTest/ConsoleAppCommandLineUtilsTest/bin/Debug/net6.0/ConsoleAppCommandLineUtilsTest.exe
如果沒有找到的話可以先在 .csproj 檔案的同層級路徑輸入下面的指令:
dotnet build
每次更改要測試都要記得重新 build 一次,不然執行檔不會更新
可選參數
字串
class Program
{
static void Main(string[] args) => CommandLineApplication.Execute<Program>(args);
private void OnExecute()
{
Console.WriteLine($"UserId: {UserId}");
}
[Option]
public string UserId { get; } ="default";
}
預設可以使用減號加變數首字母小寫(-u)或是兩個減號加上變數小寫全名使用參數。(假設變數名稱是 User,就是 --user)
如果有多個大寫,例如上面的 UserId,則以減號區隔 (--user-id)
使用方式:
也可以自訂參數名稱
[Option("-i|--Id")]
public string UserId { get; } = "default";
原本的 -u 和 --user-id 就會失效,變成新的 -i 和 --Id
數值
int 的使用方式和字串幾乎一模一樣,這裡就簡單帶過
class Program
{
static void Main(string[] args) => CommandLineApplication.Execute<Program>(args);
private void OnExecute()
{
Console.WriteLine($"Count: {Count}");
}
[Option]
public int Count { get; } = 1;
}
範例輸出:
.\ConsoleAppCommandLineUtilsTest.exe
Count: 1
.\ConsoleAppCommandLineUtilsTest.exe -c 0
Count: 0
.\ConsoleAppCommandLineUtilsTest.exe --count 100
Count: 100
布林值
class Program
{
static void Main(string[] args) => CommandLineApplication.Execute<Program>(args);
private void OnExecute()
{
Console.WriteLine($"Verbose: {Verbose}");
}
[Option]
public bool Verbose { get; }
}
預設為 false,如果使用 -v 或是 --verbose 則會變成 true , -v 和 --verbose 後面不能帶入參數
如果使用 public bool Verbose { get; } = true; 則不管有沒有帶入參數都是 True
如果想要預設值為 true,並且可以更改, 唯一的解法就是使用 CommandOptionType.SingleValue ,只是這樣後方就一定要帶入參數
[Option(CommandOptionType.SingleValue)]
public bool Verbose { get; } = true;
範例輸出:
.\ConsoleAppCommandLineUtilsTest.exe
Verbose: True
.\ConsoleAppCommandLineUtilsTest.exe -v false
Verbose: False
.\ConsoleAppCommandLineUtilsTest.exe -v true
Verbose: True
.\ConsoleAppCommandLineUtilsTest.exe --verbose false
Verbose: False
.\ConsoleAppCommandLineUtilsTest.exe --verbose true
Verbose: True
參考資料:
CommandLineUtils
留言
張貼留言
如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com