Freigeben über


Analysieren und Aufrufen in System.CommandLine

Von Bedeutung

System.CommandLine befindet sich derzeit in DER VORSCHAU, und diese Dokumentation ist für Version 2.0 Beta 5 vorgesehen. Einige Informationen beziehen sich auf vorab veröffentlichte Produkte, die vor der Veröffentlichung erheblich geändert werden können. Microsoft gibt keine Garantie, weder ausdrücklich noch impliziert, hinsichtlich der hier bereitgestellten Informationen.

System.CommandLine bietet eine klare Trennung zwischen Befehlszeilenanalyse und Aktionsaufruf. Der Analyseprozess ist für die Analyse von Befehlszeileneingaben und das Erstellen eines System.CommandLine.ParseResult Objekts verantwortlich, das die analysierten Werte (und Analysefehler) enthält. Der Aktionsaufrufprozess ist für das Aufrufen der Aktion verantwortlich, die dem analysierten Befehl, der Option oder der Direktive zugeordnet ist (Argumente können keine Aktionen haben).

Im folgenden Beispiel aus unserem Lernprogramm " Erste Schritte" System.CommandLine wird die ParseResult Durchanalyse der Befehlszeileneingabe erstellt. Es sind keine Aktionen definiert oder aufgerufen:

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);
        }
    }
}

Eine Aktion wird aufgerufen, wenn ein bestimmter Befehl (oder eine Direktive oder Option) erfolgreich analysiert wird. Bei der Aktion handelt es sich um einen Delegaten, der einen System.CommandLine.ParseResult Parameter verwendet und einen int Exitcode zurückgibt (asynchrone Aktionen sind ebenfalls verfügbar).) Der Beendigungscode wird von der System.CommandLine.Parsing.ParseResult.Invoke Methode zurückgegeben und kann verwendet werden, um anzugeben, ob der Befehl erfolgreich ausgeführt wurde oder nicht.

Im folgenden Beispiel aus unserem Lernprogramm " Erste Schritte" System.CommandLine wird die Aktion für den Stammbefehl definiert und nach der Analyse der Befehlszeileneingabe aufgerufen:

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);
        }
    }
}

Einige integrierte Symbole, z System.CommandLine.Help.HelpOption. B. , System.CommandLine.VersionOptionoder System.CommandLine.Completions.SuggestDirective, enthalten vordefinierte Aktionen. Diese Symbole werden automatisch dem Stammbefehl hinzugefügt, wenn Sie ihn erstellen, und wenn Sie die System.CommandLine.Parsing.ParseResultSymbole aufrufen, funktionieren sie einfach. Mithilfe von Aktionen können Sie sich auf Ihre App-Logik konzentrieren, während die Bibliothek die Analyse und Das Aufrufen von Aktionen für integrierte Symbole übernimmt. Wenn Es Ihnen lieber ist, können Sie sich an den Analyseprozess halten und keine Aktionen definieren (wie im ersten Beispiel oben).

Parsergebnis

Der System.CommandLine.Parsing.ParseResult Typ ist eine Klasse, die die Ergebnisse der Analyse der Befehlszeileneingabe darstellt. Sie müssen sie verwenden, um die analysierten Werte für Optionen und Argumente abzurufen (unabhängig davon, ob Sie Aktionen verwenden oder nicht). Sie können auch überprüfen, ob Analysefehler oder nicht übereinstimmende Token vorhanden sind.

Wert abrufen

Mit der System.CommandLine.Parsing.ParseResult.GetValue<T> Methode können Sie die Werte von Optionen und Argumenten abrufen:

int integer = parseResult.GetValue(delayOption);
string? message = parseResult.GetValue(messageOption);

Sie können Werte auch anhand des Namens abrufen, dies erfordert jedoch, dass Sie den Typ des abzurufenden Werts angeben.

Im folgenden Beispiel werden C#-Sammlungsinitialisierer zum Erstellen eines Stammbefehls verwendet:

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."
    }
};

Anschließend wird die GetValue Methode verwendet, um die Werte anhand des Namens abzurufen:

rootCommand.SetAction(parseResult =>
{
    int integer = parseResult.GetValue<int>("--delay");
    string? message = parseResult.GetValue<string>("--message");

    DisplayIntAndString(integer, message);
});

Diese Überladung ruft GetValue den analysierten oder Standardwert für den angegebenen Symbolnamen im Kontext des analysierten Befehls ab (nicht die gesamte Symbolstruktur). Er akzeptiert den Symbolnamen, nicht einen Alias.

Analysefehler

Die System.CommandLine.Parsing.ParseResult.Errors Eigenschaft enthält eine Liste der Analysefehler, die während des Analysevorgangs aufgetreten sind. Jeder Fehler wird durch ein System.CommandLine.Parsing.ParseError Objekt dargestellt, das Informationen zum Fehler enthält, z. B. die Fehlermeldung und das Token, das den Fehler verursacht hat.

Wenn Sie die System.CommandLine.Parsing.ParseResult.Invoke Methode aufrufen, wird ein Exitcode zurückgegeben, der angibt, ob die Analyse erfolgreich war oder nicht. Wenn Analysefehler aufgetreten sind, ist der Beendigungscode ungleich Null, und alle Analysefehler werden auf den Standardfehler gedruckt.

Wenn Sie die System.CommandLine.Parsing.ParseResult.Invoke Methode nicht aufrufen, müssen Sie die Fehler selbst behandeln, z. B. durch Drucken:

foreach (ParseError parseError in parseResult.Errors)
{
    Console.Error.WriteLine(parseError.Message);
}
return 1;

Nicht übereinstimmende Token

Die System.CommandLine.Parsing.ParseResult.UnmatchedTokens Eigenschaft enthält eine Liste der Token, die analysiert wurden, aber keinem konfigurierten Befehl, einer Option oder einem Argument entsprechen.

Die Liste der nicht übereinstimmenden Token ist nützlich bei Befehlen, die sich wie Wrapper verhalten. Ein Wrapperbefehl verwendet eine Reihe von Token und leitet sie an einen anderen Befehl oder eine andere App weiter. Der sudo Befehl in Linux ist ein Beispiel. Er verwendet den Namen eines Benutzers, um den Identitätswechsel gefolgt von einem auszuführenden Befehl auszuführen. Beispiel:

sudo -u admin apt update

Diese Befehlszeile würde den apt update Befehl als Benutzer adminausführen.

Um einen Wrapperbefehl wie diesen zu implementieren, legen Sie die Befehlseigenschaft System.CommandLine.Command.TreatUnmatchedTokensAsErrors auf false. Dann enthält die System.CommandLine.Parsing.ParseResult.UnmatchedTokens Eigenschaft alle Argumente, die nicht explizit zum Befehl gehören. Im vorherigen Beispiel ParseResult.UnmatchedTokens würden die apt Und-Token update enthalten.

Aktionen

Aktionen sind Stellvertretungen, die aufgerufen werden, wenn ein Befehl (oder eine Option oder eine Direktive) erfolgreich analysiert wird. Sie nehmen einen System.CommandLine.ParseResult Parameter und geben einen int (oder Task<int>) Ausgangscode zurück. Der Beendigungscode wird verwendet, um anzugeben, ob die Aktion erfolgreich ausgeführt wurde oder nicht.

System.CommandLine stellt eine abstrakte Basisklasse System.CommandLine.CommandLineAction und zwei abgeleitete Klassen bereit: System.CommandLine.SynchronousCommandLineAction und System.CommandLine.AsynchronousCommandLineAction. Der erste Wird für synchrone Aktionen verwendet, die einen int Exitcode zurückgeben, während letztere für asynchrone Aktionen verwendet wird, die einen Task<int> Ausgangscode zurückgeben.

Sie müssen keinen abgeleiteten Typ erstellen, um eine Aktion zu definieren. Mit der System.CommandLine.Command.SetAction Methode können Sie eine Aktion für einen Befehl festlegen. Bei der synchronen Aktion kann es sich um einen Delegaten handeln, der einen System.CommandLine.ParseResult Parameter verwendet und einen int Exit-Code zurückgibt. Die asynchrone Aktion kann eine Stellvertretung sein, die eine System.CommandLine.ParseResult und CancellationToken Parameter akzeptiert und eine .Task<int>

rootCommand.SetAction(parseResult =>
{
    FileInfo parsedFile = parseResult.GetValue(fileOption);
    ReadFile(parsedFile);
    return 0;
});

Asynchrone Aktionen

Synchrone und asynchrone Aktionen sollten nicht in derselben Anwendung gemischt werden. Wenn Sie asynchrone Aktionen verwenden möchten, muss Ihre Anwendung von oben nach unten asynchron sein. Dies bedeutet, dass alle Aktionen asynchron sein sollten, und Sie sollten die System.CommandLine.Command.SetAction Methode verwenden, die einen Delegaten akzeptiert, der einen Task<int> Ausgangscode zurückgibt. Darüber hinaus muss das CancellationToken an den Aktionsdelegat übergebene Verfahren weiter an alle Methoden übergeben werden, die abgebrochen werden können, z. B. Datei-E/A-Vorgänge oder Netzwerkanforderungen.

Darüber hinaus müssen Sie sicherstellen, dass die System.CommandLine.Parsing.ParseResult.InvokeAsync Methode anstelle von System.CommandLine.Parsing.ParseResult.Invoke. Diese Methode ist asynchron und gibt einen Task<int> Ausgangscode zurück. Sie akzeptiert auch einen optionalen CancellationToken Parameter, der zum Abbrechen der Aktion verwendet werden kann.

Im vorherigen Code wird eine SetAction Überladung verwendet, die ein ParseResult und nicht CancellationToken nur ParseResultfolgendes abruft:

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 für Prozessbeendigung

System.CommandLine.CommandLineConfiguration.ProcessTerminationTimeout ermöglicht die Signalisierung und Behandlung der Prozessbeendigung (STRG+C, SIGINT, SIGTERM), über eine CancellationToken , die während des Aufrufs an jede asynchrone Aktion übergeben wird. Sie ist standardmäßig aktiviert (2 Sekunden), sie kann jedoch so festgelegt werden, dass null sie deaktiviert wird.

Wenn die Aktion innerhalb des angegebenen Timeouts nicht abgeschlossen ist, wird der Vorgang beendet. Dies ist nützlich, um die Beendigung ordnungsgemäß zu behandeln, z. B. durch Speichern des Zustands, bevor der Prozess beendet wird.

Um den Beispielcode aus dem vorherigen Absatz zu testen, führen Sie den Befehl mit einer URL aus, die einen Moment zum Laden benötigt, und drücken Sie STRG+C, bevor der Ladevorgang abgeschlossen ist. Drücken Sie unter macOS Befehlszeitraum+(.). Beispiel:

testapp --url https://learn.microsoft.com/aspnet/core/fundamentals/minimal-apis
The operation was aborted

Exitcodes

Der Ausgangscode ist ein ganzzahliger Wert, der von einer Aktion zurückgegeben wird, die den Erfolg oder Fehler angibt. In der Konvention weist ein Exitcode 0 mit Erfolg zu, während ein beliebiger Wert ungleich Null einen Fehler angibt. Es ist wichtig, aussagekräftige Exitcodes in Ihrer Anwendung zu definieren, um den Status der Befehlsausführung klar zu kommunizieren.

Jede SetAction Methode verfügt über eine Überladung, die einen Delegaten akzeptiert, der einen int Exitcode zurückgibt, in dem der Beendigungscode explizit bereitgestellt werden muss, und eine Überladung, die zurückgegeben wird 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();
}

Siehe auch

Anpassen der Analyse und Validierung in System.CommandLineSystem.CommandLine Überblick