Condividi tramite


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:

Vedi anche