這很重要
System.CommandLine
目前為預覽版,這份文件適用於 2.0 beta 5 版。
某些資訊與發行前版本產品有關,在發行前可能會大幅修改。 Microsoft 對於此處提供的資訊,不做任何明確或隱含的保證。
System.CommandLine 提供命令行剖析和動作調用之間的清楚分隔。 剖析程式負責剖析命令行輸入,並建立 System.CommandLine.ParseResult
包含剖析值的物件(以及剖析錯誤)。 動作調用程式負責叫用與剖析命令、選項或指示詞相關聯的動作(自變數不能有動作)。
在我們的 開始使用 System.CommandLine 教學課程的下列範例中,建立 ParseResult
是透過剖析指令行輸入來完成的。 未定義或叫用任何動作:
using System.CommandLine;
using System.CommandLine.Parsing;
namespace scl;
class Program
{
static int Main(string[] args)
{
Option<FileInfo> fileOption = new("--file")
{
Description = "The file to read and display on the console."
};
RootCommand rootCommand = new("Sample app for System.CommandLine");
rootCommand.Options.Add(fileOption);
ParseResult parseResult = rootCommand.Parse(args);
if (parseResult.GetValue(fileOption) is FileInfo parsedFile)
{
ReadFile(parsedFile);
return 0;
}
foreach (ParseError parseError in parseResult.Errors)
{
Console.Error.WriteLine(parseError.Message);
}
return 1;
}
static void ReadFile(FileInfo file)
{
foreach (string line in File.ReadLines(file.FullName))
{
Console.WriteLine(line);
}
}
}
成功解析指定的命令(或指示詞或選項)時,會執行動作。 動作是接受 System.CommandLine.ParseResult
參數並傳回 int
結束代碼的委派(您也可以 使用異步動作)。 結束代碼是由 System.CommandLine.Parsing.ParseResult.Invoke
方法傳回,可用來指出命令是否成功執行。
在開始使用System.CommandLine教程的下列範例中,會針對根命令定義行動,並在解析命令列輸入之後叫用:
using System.CommandLine;
namespace scl;
class Program
{
static int Main(string[] args)
{
Option<FileInfo> fileOption = new("--file")
{
Description = "The file to read and display on the console."
};
RootCommand rootCommand = new("Sample app for System.CommandLine");
rootCommand.Options.Add(fileOption);
rootCommand.SetAction(parseResult =>
{
FileInfo parsedFile = parseResult.GetValue(fileOption);
ReadFile(parsedFile);
return 0;
});
ParseResult parseResult = rootCommand.Parse(args);
return parseResult.Invoke();
}
static void ReadFile(FileInfo file)
{
foreach (string line in File.ReadLines(file.FullName))
{
Console.WriteLine(line);
}
}
}
某些內建符號,例如 System.CommandLine.Help.HelpOption
、 System.CommandLine.VersionOption
或 System.CommandLine.Completions.SuggestDirective
,隨附預先定義的動作。 這些標誌會在您建立根命令時自動新增至根命令,而當您執行 System.CommandLine.Parsing.ParseResult
時,這些標誌便「正常運作」。使用動作可讓您專注於應用程式邏輯,而程式庫會負責剖析和執行內建標誌的動作。 如果您願意,您可以遵循剖析過程,而不定義任何動作(如上述第一個範例所示)。
ParseResult(解析結果)
此 System.CommandLine.Parsing.ParseResult
類型是類別,表示剖析命令行輸入的結果。 您必須使用它來取得選項和自變數的剖析值(無論您是否使用動作)。 您也可以檢查是否存在任何解析錯誤或不相符的標記。
GetValue
方法 System.CommandLine.Parsing.ParseResult.GetValue<T>
可讓您擷取選項和自變數的值:
int integer = parseResult.GetValue(delayOption);
string? message = parseResult.GetValue(messageOption);
您也可以依名稱取得值,但這需要您指定您想要取得的值類型。
下列範例會使用 C# 集合初始化運算式來建立根命令:
RootCommand rootCommand = new("Parameter binding example")
{
new Option<int>("--delay")
{
Description = "An option whose argument is parsed as an int."
},
new Option<string>("--message")
{
Description = "An option whose argument is parsed as a string."
}
};
然後,它會使用 GetValue
方法來依名稱取得值:
rootCommand.SetAction(parseResult =>
{
int integer = parseResult.GetValue<int>("--delay");
string? message = parseResult.GetValue<string>("--message");
DisplayIntAndString(integer, message);
});
在剖析命令的範圍內,該重載GetValue
會取得指定符號名稱的剖析值或預設值(而非整個符號樹狀結構)。 它接受符號名稱,而不是 別名。
剖析錯誤
屬性 System.CommandLine.Parsing.ParseResult.Errors
包含剖析程式期間發生的剖析錯誤清單。 每個錯誤都是由 System.CommandLine.Parsing.ParseError
物件表示,其中包含錯誤的相關信息,例如錯誤訊息和造成錯誤的令牌。
當您呼叫 System.CommandLine.Parsing.ParseResult.Invoke
方法時,它會傳回結束代碼,指出剖析是否成功。 如果有任何解析錯誤,結束代碼為非零,同時所有解析錯誤都會列印至標準錯誤。
如果您沒有呼叫 System.CommandLine.Parsing.ParseResult.Invoke
方法,您需要自行處理錯誤,例如,將錯誤列印出來:
foreach (ParseError parseError in parseResult.Errors)
{
Console.Error.WriteLine(parseError.Message);
}
return 1;
不相符的令牌
屬性 System.CommandLine.Parsing.ParseResult.UnmatchedTokens
包含一份標記清單,這些標記經過剖析但不符合任何已設定的命令、選項或參數。
不相符的令牌清單在類似包裝函式的命令中很有用。 封裝命令會採用一組 令牌,然後將其轉送至另一個命令或應用程式。
sudo
Linux 中的命令是範例。 需要提供要模擬的用戶名稱以及隨後要執行的命令。 例如:
sudo -u admin apt update
此命令行會以使用者 apt update
身分執行 admin
命令。
若要像這樣實作包裝函式命令,請將命令屬性 System.CommandLine.Command.TreatUnmatchedTokensAsErrors
設定為 false
。 然後,屬性 System.CommandLine.Parsing.ParseResult.UnmatchedTokens
將包含未明確屬於命令的所有自變數。 在上述範例中, ParseResult.UnmatchedTokens
會包含 apt
和 update
令牌。
行動
操作是在成功解析命令、選項或指示詞時被調用的委派。 他們會採用 System.CommandLine.ParseResult
參數並傳回 int
(或 Task<int>
) 結束代碼。 結束代碼是用來指出動作是否成功執行。
System.CommandLine 提供抽象基類 System.CommandLine.CommandLineAction
和兩個衍生類別: System.CommandLine.SynchronousCommandLineAction
和 System.CommandLine.AsynchronousCommandLineAction
。 前者用於傳回結束代碼的 int
同步動作,而後者則用於傳回結束代碼的 Task<int>
異步動作。
您不需要建立衍生類型來定義動作。 您可以使用 System.CommandLine.Command.SetAction
方法來設定命令的動作。 同步動作可以是接受 System.CommandLine.ParseResult
參數並回傳退出代碼的 int
委派。 異步動作可以是接受參數System.CommandLine.ParseResult
和CancellationToken並返回一個Task<int>
的委託。
rootCommand.SetAction(parseResult =>
{
FileInfo parsedFile = parseResult.GetValue(fileOption);
ReadFile(parsedFile);
return 0;
});
異步動作
同步和異步動作不應該在相同的應用程式中混合。 如果您想要使用異步動作,您的應用程式必須從上到下異步。 這表示所有動作都應該是異步的,而且您應該使用 System.CommandLine.Command.SetAction
接受傳回 Task<int>
結束代碼之委派的方法。 此外,傳遞給動作委派函式的CancellationToken必須進一步傳遞至所有可取消的方法,例如檔案 I/O 操作或網路請求。
除此之外,您必須確保使用System.CommandLine.Parsing.ParseResult.InvokeAsync
方法,而不是System.CommandLine.Parsing.ParseResult.Invoke
方法。 這個方法是異步的,並返回 Task<int>
退出代碼。 它也會接受可用來取消動作的選擇性 CancellationToken 參數。
上述程式代碼使用 SetAction
重載來取得 ParseResult 和 CancellationToken,而不只是 ParseResult
:
static Task<int> Main(string[] args)
{
Option<string> urlOption = new("--url", "A URL.");
RootCommand rootCommand = new("Handle termination example") { urlOption };
rootCommand.SetAction((ParseResult parseResult, CancellationToken cancellationToken) =>
{
string? urlOptionValue = parseResult.GetValue(urlOption);
return DoRootCommand(urlOptionValue, cancellationToken);
});
return rootCommand.Parse(args).InvokeAsync();
}
public static async Task<int> DoRootCommand(
string? urlOptionValue, CancellationToken cancellationToken)
{
using HttpClient httpClient = new();
try
{
await httpClient.GetAsync(urlOptionValue, cancellationToken);
return 0;
}
catch (OperationCanceledException)
{
await Console.Error.WriteLineAsync("The operation was aborted");
return 1;
}
}
進程終止逾時
System.CommandLine.CommandLineConfiguration.ProcessTerminationTimeout
在調用期間傳遞給每個異步操作的,啟用進程終止訊號的處理(+SIGINT
、SIGTERM
CancellationToken)。 默認會啟用它 (2 秒),但您可以將它設定為 null
停用它。
啟用時,如果動作未在指定的逾時內完成,進程將會終止。 在終止進程之前儲存狀態等措施,有助於優雅地處理終止過程。
若要測試上一段的範例程式代碼,請使用URL執行命令,該URL需要一些時間才能載入,然後在載入完成之前,按 Ctrl+C。 在macOS上,按 Command+句號(.)。 例如:
testapp --url https://learn.microsoft.com/aspnet/core/fundamentals/minimal-apis
The operation was aborted
出口代碼
結束代碼是動作所傳回的整數值,指出其成功或失敗。 依照慣例,結束代碼 0
表示成功,而任何非零值則表示錯誤。 請務必在應用程式中定義有意義的結束代碼,以清楚傳達命令執行的狀態。
每個 SetAction
方法都有一個多載,該多載可接受傳回 int
結束代碼的委派,結束代碼需要以明確的方式提供,以及一個多載傳回 0
。
static int Main(string[] args)
{
Option<int> delayOption = new("--delay");
Option<string> messageOption = new("--message");
RootCommand rootCommand = new("Parameter binding example")
{
delayOption,
messageOption
};
rootCommand.SetAction(parseResult =>
{
Console.WriteLine($"--delay = {parseResult.GetValue(delayOption)}");
Console.WriteLine($"--message = {parseResult.GetValue(messageOption)}");
// Value returned from the action delegate is the exit code.
return 100;
});
return rootCommand.Parse(args).Invoke();
}