Come definire comandi, opzioni e argomenti in System.CommandLine
Importante
System.CommandLine
è attualmente in ANTEPRIMA e questa documentazione si riferisce alla versione 2.0 beta 4.
Alcune informazioni riguardano il prodotto in versione non definitiva e potrebbe essere modificate in modo sostanziale prima del rilascio. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.
Questo articolo illustra come definire i comandi, le opzionie gli argomenti nelle app da riga di comando compilate con la libreria System.CommandLine
. Per compilare un'applicazione completa che illustra queste tecniche, vedere l'esercitazione Introduzione a System.CommandLine.
Per indicazioni su come progettare comandi, opzioni e argomenti di un'app da riga di comando, vedere Linee guida per la progettazione.
Definire un comando radice
Ogni app della riga di comando ha un comando radice, che fa riferimento al file eseguibile stesso. Il caso più semplice per richiamare il codice, se si dispone di un'app senza sottocomandi, opzioni o argomenti, è il seguente:
using System.CommandLine;
class Program
{
static async Task Main(string[] args)
{
var rootCommand = new RootCommand("Sample command-line app");
rootCommand.SetHandler(() =>
{
Console.WriteLine("Hello world!");
});
await rootCommand.InvokeAsync(args);
}
}
Definire sottocomandi
I comandi possono avere comandi figlio, noti come sottocomandi o verbi, e possono annidare tutti i livelli necessari. È possibile aggiungere sottocomandi come illustrato nell'esempio seguente:
var rootCommand = new RootCommand();
var sub1Command = new Command("sub1", "First-level subcommand");
rootCommand.Add(sub1Command);
var sub1aCommand = new Command("sub1a", "Second level subcommand");
sub1Command.Add(sub1aCommand);
Il sottocomando più interno in questo esempio può essere richiamato come segue:
myapp sub1 sub1a
Definire le opzioni
Un metodo del gestore dei comandi include in genere parametri e i valori possono provenire dalle opzioni della riga di comando. Nell'esempio seguente vengono create due opzioni e vengono aggiunte al comando radice. I nomi delle opzioni includono prefissi con trattino doppio, che è tipico delle interfacce della riga di comando POSIX. Il codice del gestore dei comandi visualizza i valori di queste opzioni:
var delayOption = new Option<int>
(name: "--delay",
description: "An option whose argument is parsed as an int.",
getDefaultValue: () => 42);
var messageOption = new Option<string>
("--message", "An option whose argument is parsed as a string.");
var rootCommand = new RootCommand();
rootCommand.Add(delayOption);
rootCommand.Add(messageOption);
rootCommand.SetHandler((delayOptionValue, messageOptionValue) =>
{
Console.WriteLine($"--delay = {delayOptionValue}");
Console.WriteLine($"--message = {messageOptionValue}");
},
delayOption, messageOption);
Ecco un esempio di input da riga di comando e di output risultante per il codice di esempio precedente:
myapp --delay 21 --message "Hello world!"
--delay = 21
--message = Hello world!
Opzioni globali
Per aggiungere un'opzione a un comando alla volta, usare il metodo Add
o AddOption
come illustrato nell'esempio precedente. Per aggiungere un'opzione a un comando e in modo ricorsivo a tutti i relativi sottocomandi, usare il metodo AddGlobalOption
, come illustrato nell'esempio seguente:
var delayOption = new Option<int>
("--delay", "An option whose argument is parsed as an int.");
var messageOption = new Option<string>
("--message", "An option whose argument is parsed as a string.");
var rootCommand = new RootCommand();
rootCommand.AddGlobalOption(delayOption);
rootCommand.Add(messageOption);
var subCommand1 = new Command("sub1", "First level subcommand");
rootCommand.Add(subCommand1);
var subCommand1a = new Command("sub1a", "Second level subcommand");
subCommand1.Add(subCommand1a);
subCommand1a.SetHandler((delayOptionValue) =>
{
Console.WriteLine($"--delay = {delayOptionValue}");
},
delayOption);
await rootCommand.InvokeAsync(args);
Il codice precedente aggiunge --delay
come opzione globale al comando radice ed è disponibile nel gestore per subCommand1a
.
Definire gli argomenti
Gli argomenti vengono definiti e aggiunti a comandi come opzioni. L'esempio seguente è simile a quello delle opzioni, ma definisce gli argomenti anziché le opzioni:
var delayArgument = new Argument<int>
(name: "delay",
description: "An argument that is parsed as an int.",
getDefaultValue: () => 42);
var messageArgument = new Argument<string>
("message", "An argument that is parsed as a string.");
var rootCommand = new RootCommand();
rootCommand.Add(delayArgument);
rootCommand.Add(messageArgument);
rootCommand.SetHandler((delayArgumentValue, messageArgumentValue) =>
{
Console.WriteLine($"<delay> argument = {delayArgumentValue}");
Console.WriteLine($"<message> argument = {messageArgumentValue}");
},
delayArgument, messageArgument);
await rootCommand.InvokeAsync(args);
Ecco un esempio di input da riga di comando e di output risultante per il codice di esempio precedente:
myapp 42 "Hello world!"
<delay> argument = 42
<message> argument = Hello world!
Un argomento definito senza un valore predefinito, come messageArgument
nell'esempio precedente, viene trattato come un argomento obbligatorio. Se non viene fornito un argomento obbligatorio, viene visualizzato un messaggio di errore e il gestore del comando non viene chiamato.
Definire gli alias
Entrambi i comandi e le opzioni supportano gli alias. È possibile aggiungere un alias a un'opzione chiamando AddAlias
:
var option = new Option("--framework");
option.AddAlias("-f");
Dato questo alias, le righe di comando seguenti sono equivalenti:
myapp -f net6.0
myapp --framework net6.0
Gli alias di comando funzionano allo stesso modo.
var command = new Command("serialize");
command.AddAlias("serialise");
Questo codice rende equivalenti le righe di comando seguenti:
myapp serialize
myapp serialise
È consigliabile ridurre al minimo il numero di alias di opzioni definiti e di evitare di definire determinati alias in particolare. Per altre informazioni, vedere Alias in formato breve.
Opzioni obbligatorie
Per rendere obbligatoria un'opzione, impostare la relativa proprietà IsRequired
su true
, come illustrato nell'esempio seguente:
var endpointOption = new Option<Uri>("--endpoint") { IsRequired = true };
var command = new RootCommand();
command.Add(endpointOption);
command.SetHandler((uri) =>
{
Console.WriteLine(uri?.GetType());
Console.WriteLine(uri?.ToString());
},
endpointOption);
await command.InvokeAsync(args);
La sezione opzioni della guida del comando indica che l'opzione è necessaria:
Options:
--endpoint <uri> (REQUIRED)
--version Show version information
-?, -h, --help Show help and usage information
Se la riga di comando di questa applicazione di esempio non include --endpoint
, viene visualizzato un messaggio di errore e il gestore di comandi non viene chiamato:
Option '--endpoint' is required.
Se un'opzione obbligatoria ha un valore predefinito, non è necessario specificare l'opzione nella riga di comando. In tal caso, il valore predefinito fornisce il valore dell'opzione richiesta.
Comandi, opzioni e argomenti nascosti
Potrebbe essere necessario supportare un comando, un'opzione o un argomento, ma evitare di renderlo facilmente individuabile. Ad esempio, potrebbe trattarsi di una funzionalità di anteprima deprecata, amministrativa o di anteprima. Usare la proprietà IsHidden per impedire agli utenti di individuare tali funzionalità usando il completamento delle schede o la guida, come illustrato nell'esempio seguente:
var endpointOption = new Option<Uri>("--endpoint") { IsHidden = true };
var command = new RootCommand();
command.Add(endpointOption);
command.SetHandler((uri) =>
{
Console.WriteLine(uri?.GetType());
Console.WriteLine(uri?.ToString());
},
endpointOption);
await command.InvokeAsync(args);
La sezione opzioni del comando di questo esempio omette l'opzione --endpoint
.
Options:
--version Show version information
-?, -h, --help Show help and usage information
Impostare l'arità dell'argomento
È possibile impostare l'arità dell'argomento in modo esplicito usando la proprietà Arity
, ma nella maggior parte dei casi non è necessario. System.CommandLine
determina automaticamente l'arità dell'argomento in base al tipo di argomento:
Tipo di argomento | Arità predefinita |
---|---|
Boolean |
ArgumentArity.ZeroOrOne |
Tipi di raccolta | ArgumentArity.ZeroOrMore |
Tutti gli altri elementi | ArgumentArity.ExactlyOne |
Argomenti multipli
Per impostazione predefinita, quando si chiama un comando, è possibile ripetere il nome di un'opzione per specificare più argomenti per un'opzione con un'arità massima maggiore di uno.
myapp --items one --items two --items three
Per consentire più argomenti senza ripetere il nome dell'opzione, impostare Option.AllowMultipleArgumentsPerToken su true
. Questa impostazione consente di immettere la riga di comando seguente.
myapp --items one two three
La stessa impostazione ha un effetto diverso se l'arità massima dell'argomento è 1. Consente di ripetere un'opzione, ma accetta solo l'ultimo valore sulla riga. Nell'esempio seguente il valore three
viene passato all'app.
myapp --item one --item two --item three
Elencare i valori validi degli argomenti
Per specificare un elenco di valori validi per un'opzione o un argomento, specificare un'enumerazione come tipo di opzione o usare FromAmong, come illustrato nell'esempio seguente:
var languageOption = new Option<string>(
"--language",
"An option that that must be one of the values of a static list.")
.FromAmong(
"csharp",
"fsharp",
"vb",
"pwsh",
"sql");
Ecco un esempio di input da riga di comando e di output risultante per il codice di esempio precedente:
myapp --language not-a-language
Argument 'not-a-language' not recognized. Must be one of:
'csharp'
'fsharp'
'vb'
'pwsh'
'sql'
La sezione opzioni della Guida ai comandi mostra i valori validi:
Options:
--language <csharp|fsharp|vb|pwsh|sql> An option that must be one of the values of a static list.
--version Show version information
-?, -h, --help Show help and usage information
Convalida di opzioni e argomenti
Per informazioni sulla convalida degli argomenti e su come personalizzarla, vedere le sezioni seguenti nell'articolo Binding dei parametri: