Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Importante
System.CommandLine
è attualmente disponibile in ANTEPRIMA e questa documentazione è per la versione 2.0 beta 5.
Alcune informazioni riguardano il prodotto in fase di pre-rilascio che potrebbe essere modificato in modo sostanziale prima del rilascio. Microsoft non fornisce alcuna garanzia, espressa o implicita, in relazione alle informazioni fornite qui.
System.CommandLine offre una netta separazione tra l'analisi della riga di comando e la chiamata all'azione. Il processo di analisi è responsabile dell'analisi dell'input della riga di comando e della creazione di un System.CommandLine.ParseResult
oggetto contenente i valori analizzati (e analizzare gli errori). Il processo di chiamata all'azione è responsabile della chiamata dell'azione associata al comando analizzato, all'opzione o alla direttiva (gli argomenti non possono avere azioni).
Nell'esempio seguente dell'esercitazione Introduzione System.CommandLine, ParseResult
viene creato analizzando l'input della riga di comando. Non vengono definite o richiamate azioni:
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);
}
}
}
Un'azione viene richiamata quando un determinato comando (o direttiva o opzione) viene analizzato correttamente. L'azione è un delegato che accetta un System.CommandLine.ParseResult
parametro e restituisce un int
codice di uscita (sono disponibili anche azioni asincrone). Il codice di uscita viene restituito dal System.CommandLine.Parsing.ParseResult.Invoke
metodo e può essere usato per indicare se il comando è stato eseguito correttamente o meno.
Nell'esempio seguente tratto dal nostro tutorial Introduzione System.CommandLine, l'azione viene definita per il comando radice e richiamata dopo l'analisi dell'input della riga di comando.
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);
}
}
}
Alcuni simboli predefiniti, ad esempio System.CommandLine.Help.HelpOption
, System.CommandLine.VersionOption
o System.CommandLine.Completions.SuggestDirective
, sono dotati di azioni predefinite. Questi simboli vengono aggiunti automaticamente al comando radice quando lo si crea e quando si richiama System.CommandLine.Parsing.ParseResult
, essi "funzionano semplicemente". L'uso delle azioni consente di concentrarsi sulla logica dell'app, mentre la libreria si occupa dell'analisi e della chiamata di azioni per i simboli predefiniti. Se si preferisce, è possibile attenersi al processo di analisi e non definire alcuna azione (come nel primo esempio precedente).
ParseResult
Il System.CommandLine.Parsing.ParseResult
tipo è una classe che rappresenta i risultati dell'analisi dell'input della riga di comando. È necessario usarlo per ottenere i valori analizzati per le opzioni e gli argomenti ,indipendentemente dal fatto che si usino o meno azioni. È anche possibile verificare se sono presenti errori di analisi o token non corrispondenti.
GetValue
Il System.CommandLine.Parsing.ParseResult.GetValue<T>
metodo consente di recuperare i valori delle opzioni e degli argomenti:
int integer = parseResult.GetValue(delayOption);
string? message = parseResult.GetValue(messageOption);
È anche possibile ottenere valori in base al nome, ma è necessario specificare il tipo del valore che si vuole ottenere.
L'esempio seguente usa gli inizializzatori di raccolta C# per creare un comando radice:
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."
}
};
Usa quindi il GetValue
metodo per ottenere i valori in base al nome:
rootCommand.SetAction(parseResult =>
{
int integer = parseResult.GetValue<int>("--delay");
string? message = parseResult.GetValue<string>("--message");
DisplayIntAndString(integer, message);
});
Questo overload di GetValue
ottiene il valore analizzato o predefinito per il nome del simbolo specificato, nel contesto del comando analizzato (non l'intero albero dei simboli). Accetta il nome del simbolo, non un alias.
Analizzare gli errori
La System.CommandLine.Parsing.ParseResult.Errors
proprietà contiene un elenco di errori di analisi che si sono verificati durante il processo di analisi. Ogni errore è rappresentato da un System.CommandLine.Parsing.ParseError
oggetto , che contiene informazioni sull'errore, ad esempio il messaggio di errore e il token che ha causato l'errore.
Quando si chiama il System.CommandLine.Parsing.ParseResult.Invoke
metodo, restituisce un codice di uscita che indica se l'analisi è riuscita o meno. Se ci sono errori di parsing, il codice di uscita è diverso da zero e tutti gli errori di parsing vengono stampati nello standard error.
Se non si richiama il System.CommandLine.Parsing.ParseResult.Invoke
metodo , è necessario gestire gli errori autonomamente, ad esempio stampandoli:
foreach (ParseError parseError in parseResult.Errors)
{
Console.Error.WriteLine(parseError.Message);
}
return 1;
Token non corrispondenti
La System.CommandLine.Parsing.ParseResult.UnmatchedTokens
proprietà contiene un elenco dei token analizzati ma che non corrispondono ad alcun comando, opzione o argomento configurato.
L'elenco di token non corrispondenti è utile nei comandi che si comportano come wrapper. Un comando wrapper accetta un set di token e li inoltra a un altro comando o app. Il sudo
comando in Linux è un esempio. Richiede il nome di un utente da impersonare seguito da un comando da eseguire. Per esempio:
sudo -u admin apt update
Questa riga di comando eseguirà il apt update
comando come utente admin
.
Per implementare un comando wrapper come questo, impostare la proprietà System.CommandLine.Command.TreatUnmatchedTokensAsErrors
del comando su false
. La System.CommandLine.Parsing.ParseResult.UnmatchedTokens
proprietà conterrà quindi tutti gli argomenti che non appartengono in modo esplicito al comando. Nell'esempio precedente, ParseResult.UnmatchedTokens
conterrà i token apt
e update
.
Azioni
Le azioni sono delegati richiamati quando un comando (o un'opzione o una direttiva) viene analizzato correttamente. Accettano un System.CommandLine.ParseResult
parametro e restituiscono un int
codice di uscita (o Task<int>
). Il codice di uscita viene usato per indicare se l'azione è stata eseguita correttamente o meno.
System.CommandLine fornisce una classe System.CommandLine.CommandLineAction
base astratta e due classi derivate: System.CommandLine.SynchronousCommandLineAction
e System.CommandLine.AsynchronousCommandLineAction
. Il primo viene usato per le azioni sincrone che restituiscono un int
codice di uscita, mentre quest'ultimo viene usato per azioni asincrone che restituiscono un Task<int>
codice di uscita.
Non è necessario creare un tipo derivato per definire un'azione. È possibile usare il System.CommandLine.Command.SetAction
metodo per impostare un'azione per un comando. L'azione sincrona può essere un delegato che accetta un System.CommandLine.ParseResult
parametro e restituisce un int
codice di uscita. L'azione asincrona può essere un delegato che accetta parametri System.CommandLine.ParseResult
e CancellationToken e restituisce un oggetto Task<int>
.
rootCommand.SetAction(parseResult =>
{
FileInfo parsedFile = parseResult.GetValue(fileOption);
ReadFile(parsedFile);
return 0;
});
Azioni asincrone
Le azioni sincrone e asincrone non devono essere miste nella stessa applicazione. Se si vogliono usare azioni asincrone, l'applicazione deve essere asincrona dall'alto verso il basso. Ciò significa che tutte le azioni devono essere asincrone ed è necessario usare il System.CommandLine.Command.SetAction
metodo che accetta un delegato che restituisce un Task<int>
codice di uscita. Inoltre, l'oggetto CancellationToken passato al delegato di azione deve essere passato ulteriormente a tutti i metodi che possono essere annullati, ad esempio operazioni di I/O file o richieste di rete.
Oltre a questo, è necessario assicurarsi che il System.CommandLine.Parsing.ParseResult.InvokeAsync
metodo venga usato invece di System.CommandLine.Parsing.ParseResult.Invoke
. Questo metodo è asincrono e restituisce un Task<int>
codice di uscita. Accetta anche un parametro facoltativo CancellationToken che può essere usato per annullare l'azione.
Il codice precedente usa un SetAction
overload che ottiene un ParseResult e un CancellationToken anziché semplicemente 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;
}
}
Timeout di terminazione del processo
System.CommandLine.CommandLineConfiguration.ProcessTerminationTimeout
abilita la segnalazione e la gestione della terminazione del processo (CTRL+C, SIGINT
, SIGTERM
) tramite un CancellationToken oggetto passato a ogni azione asincrona durante la chiamata. È abilitato per impostazione predefinita (2 secondi), ma è possibile impostarlo su null
per disabilitarlo.
Se abilitata, se l'azione non viene completata entro il timeout specificato, il processo verrà terminato. Ciò è utile per gestire correttamente la terminazione, ad esempio salvando lo stato prima che il processo venga terminato.
Per testare il codice di esempio del paragrafo precedente, eseguire il comando con un URL che richiederà un po' di tempo per il caricamento e prima di completare il caricamento, premere CTRL+C. Su macOS premere Comando++Punto (.). Per esempio:
testapp --url https://learn.microsoft.com/aspnet/core/fundamentals/minimal-apis
The operation was aborted
Codici di uscita
Il codice di uscita è un valore intero restituito da un'azione che indica l'esito positivo o negativo. Per convenzione, un codice di uscita di 0
indica l'esito positivo, mentre qualsiasi valore diverso da zero indica un errore. È importante definire codici di uscita significativi nell'applicazione per comunicare chiaramente lo stato dell'esecuzione dei comandi.
Ogni metodo SetAction
ha un sovraccarico che accetta un delegato che restituisce un codice di uscita int
dove il codice di uscita deve essere fornito in maniera esplicita e un sovraccarico che restituisce 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();
}
Vedere anche
Come personalizzare l'analisi e la convalida in System.CommandLineSystem.CommandLine panoramica