Tutorial: Erste Schritte mit System.CommandLine

Wichtig

System.CommandLine befindet sich derzeit in der VORSCHAU, und diese Dokumentation gilt für Version 2.0 Beta 4. Einige Informationen beziehen sich auf Vorabversionen des Produkts, die vor dem Release ggf. grundlegend überarbeitet werden. Microsoft übernimmt hinsichtlich der hier bereitgestellten Informationen keine Gewährleistungen, seien sie ausdrücklich oder konkludent.

In diesem Tutorial wird erläutert, wie Sie eine .NET-Befehlszeilen-App erstellen, die die System.CommandLine-Bibliothek verwendet. Sie beginnen mit dem Erstellen eines einfachen Stammbefehls, der eine Option umfasst. Basierend auf dieser Grundlage erstellen Sie anschließend eine komplexere App, die mehrere Unterbefehle und verschiedene Optionen für jeden Befehl enthält.

In diesem Tutorial lernen Sie Folgendes:

  • Erstellen von Befehlen, Optionen und Argumenten
  • Angeben der Standardwerte für Optionen
  • Zuweisen von Optionen und Argumenten zu Befehlen
  • Rekursives Zuweisen einer Option zu allen Unterbefehlen eines Befehls
  • Arbeiten mit mehreren Ebenen geschachtelter Unterbefehle
  • Erstellen von Aliasen für Befehle und Optionen
  • Arbeiten mit string, string[], int, bool und FileInfo sowie Enumerationsoptionstypen
  • Binden von Optionswerten an Befehlshandlercode
  • Verwenden von benutzerdefiniertem Code für das Analysieren und Überprüfen von Optionen

Voraussetzungen

oder

Erstellen der App

Erstellen Sie ein .NET 6-Konsolen-App-Projekt namens „scl“.

  1. Erstellen Sie einen Ordner mit dem Namen scl für das Projekt, und öffnen Sie dann eine Eingabeaufforderung im neuen Ordner.

  2. Führen Sie den folgenden Befehl aus:

    dotnet new console --framework net6.0
    

Installieren Sie das Paket System.CommandLine.

  • Führen Sie den folgenden Befehl aus:

    dotnet add package System.CommandLine --prerelease
    

    Die --prerelease-Option ist erforderlich, da sich die Bibliothek noch in der Betaversion befindet.

  1. Ersetzen Sie den Inhalt von Program.cs durch den folgenden Code:

    using System.CommandLine;
    
    namespace scl;
    
    class Program
    {
        static async Task<int> Main(string[] args)
        {
            var fileOption = new Option<FileInfo?>(
                name: "--file",
                description: "The file to read and display on the console.");
    
            var rootCommand = new RootCommand("Sample app for System.CommandLine");
            rootCommand.AddOption(fileOption);
    
            rootCommand.SetHandler((file) => 
                { 
                    ReadFile(file!); 
                },
                fileOption);
    
            return await rootCommand.InvokeAsync(args);
        }
    
        static void ReadFile(FileInfo file)
        {
            File.ReadLines(file.FullName).ToList()
                .ForEach(line => Console.WriteLine(line));
        }
    }
    

Der vorangehende Code:

  • Hiermit wird eine Option namens --file vom Typ FileInfo erstellt und dem Stammbefehl zugewiesen:

    var fileOption = new Option<FileInfo?>(
        name: "--file",
        description: "The file to read and display on the console.");
    
    var rootCommand = new RootCommand("Sample app for System.CommandLine");
    rootCommand.AddOption(fileOption);
    
  • Hiermit wird angegeben, dass ReadFile die Methode ist, die beim Aufruf des Stammbefehls aufgerufen wird:

    rootCommand.SetHandler((file) => 
        { 
            ReadFile(file!); 
        },
        fileOption);
    
  • Hiermit wird der Inhalt der angegebenen Datei angezeigt, wenn der Stammbefehl aufgerufen wird:

    static void ReadFile(FileInfo file)
    {
        File.ReadLines(file.FullName).ToList()
            .ForEach(line => Console.WriteLine(line));
    }
    

Testen der App

Sie können eine der folgenden Möglichkeiten zum Testen während der Entwicklung einer Befehlszeilen-App verwenden:

  • Führen Sie den dotnet build-Befehl aus, und öffnen Sie dann eine Eingabeaufforderung im Ordner scl/bin/Debug/net6.0, um die ausführbare Datei auszuführen:

    dotnet build
    cd bin/Debug/net6.0
    scl --file scl.runtimeconfig.json
    
  • Verwenden Sie dotnet run, und übergeben Sie Optionswerte anstelle des run-Befehls an die App, indem Sie sie wie im folgenden Beispiel gezeigt nach -- einschließen:

    dotnet run -- --file scl.runtimeconfig.json
    

    In .NET 7.0.100 SDK Preview können Sie die commandLineArgs einer launchSettings.json-Datei verwenden, indem Sie den Befehl dotnet run --launch-profile <profilename> ausführen.

  • Veröffentlichen Sie das Projekt in einem Ordner, öffnen Sie eine Eingabeaufforderung für diesen Ordner, und führen Sie die ausführbare Datei aus:

    dotnet publish -o publish
    cd ./publish
    scl --file scl.runtimeconfig.json
    
  • Wählen Sie in Visual Studio 2022 im Menü Debuggen>Debugeigenschaften aus, und geben Sie die Optionen und Argumente in das Feld Befehlszeilenargumente ein. Zum Beispiel:

    Befehlszeilenargumente in Visual Studio 2022

    Führen Sie dann die App aus (z. B. durch Drücken von STRG+F5).

In diesem Tutorial wird davon ausgegangen, dass Sie die erste dieser Optionen verwenden.

Wenn Sie die App ausführen, wird der Inhalt der durch die --file-Option angegebenen Datei angezeigt.

{
  "runtimeOptions": {
    "tfm": "net6.0",
    "framework": {
      "name": "Microsoft.NETCore.App",
      "version": "6.0.0"
    }
  }
}

Hilfeausgabe

System.CommandLine stellt automatisch eine Hilfeausgabe bereit:

scl --help
Description:
  Sample app for System.CommandLine

Usage:
  scl [options]

Options:
  --file <file>   The file to read and display on the console.
  --version       Show version information
  -?, -h, --help  Show help and usage information

Versionsausgabe

System.CommandLine stellt automatisch die Versionsausgabe bereit:

scl --version
1.0.0

Hinzufügen eines Unterbefehls und von Optionen

In diesem Abschnitt führen Sie folgende Schritte aus:

  • Erstellen weiterer Optionen
  • Erstellen eines Unterbefehls
  • Zuweisen der neuen Optionen zu einem Unterbefehl

Mit den neuen Optionen können Sie die Vordergrund- und Hintergrundtextfarben und die Lesegeschwindigkeit konfigurieren. Diese Features werden verwendet, um eine Sammlung von Zitaten zu lesen, die aus dem Tutorial für eine Teleprompter-Konsolen-App stammen.

  1. Kopieren Sie die Datei sampleQuotes.txt aus dem GitHub-Repository für dieses Beispiel in Ihr Projektverzeichnis. Informationen zum Herunterladen von Dateien finden Sie in den Anweisungen unter Beispiele und Tutorials.

  2. Öffnen Sie die Projektdatei, und fügen Sie direkt vor dem schließenden </Project>-Tag ein <ItemGroup>-Element hinzu:

    <ItemGroup>
      <Content Include="sampleQuotes.txt">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      </Content>
    </ItemGroup>
    

    Wenn Sie dieses Markup hinzufügen, wird die Textdatei beim Erstellen der App in den Ordner bin/debug/net6.0 kopiert. Wenn Sie also die ausführbare Datei in diesem Ordner ausführen, können Sie nach Name auf die Datei zugreifen, ohne einen Ordnerpfad anzugeben.

  3. Erstellen Sie in Program.cs nach dem Code, der die --file-Option erstellt, Optionen zum Konfigurieren der Lesegeschwindigkeit und der Textfarben:

    var delayOption = new Option<int>(
        name: "--delay",
        description: "Delay between lines, specified as milliseconds per character in a line.",
        getDefaultValue: () => 42);
    
    var fgcolorOption = new Option<ConsoleColor>(
        name: "--fgcolor",
        description: "Foreground color of text displayed on the console.",
        getDefaultValue: () => ConsoleColor.White);
    
    var lightModeOption = new Option<bool>(
        name: "--light-mode",
        description: "Background color of text displayed on the console: default is black, light mode is white.");
    
  4. Löschen Sie nach der Zeile, die den Stammbefehl erstellt, die Zeile, mit der ihr die --file-Option hinzugefügt wird. Sie entfernen die Zeile an dieser Stelle, da Sie sie einem neuen Unterbefehl hinzufügen.

    var rootCommand = new RootCommand("Sample app for System.CommandLine");
    //rootCommand.AddOption(fileOption);
    
  5. Erstellen Sie nach der Zeile, die den Stammbefehl erstellt, einen read-Unterbefehl. Fügen Sie diesem Unterbefehl die Optionen hinzu, und fügen Sie dem Stammbefehl den Unterbefehl hinzu.

    var readCommand = new Command("read", "Read and display the file.")
        {
            fileOption,
            delayOption,
            fgcolorOption,
            lightModeOption
        };
    rootCommand.AddCommand(readCommand);
    
  6. Ersetzen Sie den SetHandler-Code durch den folgenden SetHandler-Code für den neuen Unterbefehl:

    readCommand.SetHandler(async (file, delay, fgcolor, lightMode) =>
        {
            await ReadFile(file!, delay, fgcolor, lightMode);
        },
        fileOption, delayOption, fgcolorOption, lightModeOption);
    

    Sie rufen SetHandler nicht mehr für den Stammbefehl auf, da der Stammbefehl keinen Handler mehr benötigt. Wenn ein Befehl Unterbefehle aufweist, müssen Sie in der Regel einen der Unterbefehle angeben, wenn Sie eine Befehlszeilen-App aufrufen.

  7. Ersetzen Sie die ReadFile-Handlermethode durch den folgenden Code:

    internal static async Task ReadFile(
            FileInfo file, int delay, ConsoleColor fgColor, bool lightMode)
    {
        Console.BackgroundColor = lightMode ? ConsoleColor.White : ConsoleColor.Black;
        Console.ForegroundColor = fgColor;
        List<string> lines = File.ReadLines(file.FullName).ToList();
        foreach (string line in lines)
        {
            Console.WriteLine(line);
            await Task.Delay(delay * line.Length);
        };
    }
    

Die App sieht nun wie folgt aus:

using System.CommandLine;

namespace scl;

class Program
{
    static int Main(string[] args)
    {
        var fileOption = new Option<FileInfo?>(
            name: "--file",
            description: "The file to read and display on the console.");

        var delayOption = new Option<int>(
            name: "--delay",
            description: "Delay between lines, specified as milliseconds per character in a line.",
            getDefaultValue: () => 42);

        var fgcolorOption = new Option<ConsoleColor>(
            name: "--fgcolor",
            description: "Foreground color of text displayed on the console.",
            getDefaultValue: () => ConsoleColor.White);

        var lightModeOption = new Option<bool>(
            name: "--light-mode",
            description: "Background color of text displayed on the console: default is black, light mode is white.");

        var rootCommand = new RootCommand("Sample app for System.CommandLine");
        //rootCommand.AddOption(fileOption);

        var readCommand = new Command("read", "Read and display the file.")
            {
                fileOption,
                delayOption,
                fgcolorOption,
                lightModeOption
            };
        rootCommand.AddCommand(readCommand);

        readCommand.SetHandler(async (file, delay, fgcolor, lightMode) =>
            {
                await ReadFile(file!, delay, fgcolor, lightMode);
            },
            fileOption, delayOption, fgcolorOption, lightModeOption);

        return rootCommand.InvokeAsync(args).Result;
    }

    internal static async Task ReadFile(
            FileInfo file, int delay, ConsoleColor fgColor, bool lightMode)
    {
        Console.BackgroundColor = lightMode ? ConsoleColor.White : ConsoleColor.Black;
        Console.ForegroundColor = fgColor;
        List<string> lines = File.ReadLines(file.FullName).ToList();
        foreach (string line in lines)
        {
            Console.WriteLine(line);
            await Task.Delay(delay * line.Length);
        };
    }
}

Testen des neuen Unterbefehls

Wenn Sie nun versuchen, die App auszuführen, ohne den Unterbefehl anzugeben, wird eine Fehlermeldung gefolgt von einer Hilfemeldung angezeigt, die den verfügbaren Unterbefehl angibt.

scl --file sampleQuotes.txt
'--file' was not matched. Did you mean one of the following?
--help
Required command was not provided.
Unrecognized command or argument '--file'.
Unrecognized command or argument 'sampleQuotes.txt'.

Description:
  Sample app for System.CommandLine

Usage:
  scl [command] [options]

Options:
  --version       Show version information
  -?, -h, --help  Show help and usage information

Commands:
  read  Read and display the file.

Der Hilfetext für den Unterbefehl read gibt an, dass vier Optionen verfügbar sind. Es werden gültige Werte für die Enumeration angezeigt.

scl read -h
Description:
  Read and display the file.

Usage:
  scl read [options]

Options:
  --file <file>                                               The file to read and display on the console.
  --delay <delay>                                             Delay between lines, specified as milliseconds per
                                                              character in a line. [default: 42]
  --fgcolor                                                   Foreground color of text displayed on the console.
  <Black|Blue|Cyan|DarkBlue|DarkCyan|DarkGray|DarkGreen|Dark  [default: White]
  Magenta|DarkRed|DarkYellow|Gray|Green|Magenta|Red|White|Ye
  llow>
  --light-mode                                                Background color of text displayed on the console:
                                                              default is black, light mode is white.
  -?, -h, --help                                              Show help and usage information

Führen Sie den Unterbefehl read aus, der nur die --file-Option angibt, und Sie erhalten die Standardwerte für die anderen drei Optionen.

scl read --file sampleQuotes.txt

Die Standardverzögerung von 42 Millisekunden pro Zeichen führt zu einer langsamen Lesegeschwindigkeit. Sie können dies beschleunigen, indem Sie --delay auf eine niedrigere Zahl festlegen.

scl read --file sampleQuotes.txt --delay 0

Sie können --fgcolor und --light-mode verwenden, um die Textfarben festzulegen:

scl read --file sampleQuotes.txt --fgcolor red --light-mode

Geben Sie einen ungültigen Wert für --delay ein, und Sie erhalten eine Fehlermeldung:

scl read --file sampleQuotes.txt --delay forty-two
Cannot parse argument 'forty-two' for option '--int' as expected type 'System.Int32'.

Geben Sie einen ungültigen Wert für --file ein, und Sie erhalten eine Ausnahme:

scl read --file nofile
Unhandled exception: System.IO.FileNotFoundException:
Could not find file 'C:\bin\Debug\net6.0\nofile'.

Hinzufügen von Unterbefehlen und benutzerdefinierte Überprüfung

In diesem Abschnitt wird die endgültige Version der App erstellt. Nach Abschluss des Vorgangs umfasst die App die folgenden Befehle und Optionen:

  • Stammbefehl mit einer globalen* Option namens --file
    • quotes-Befehl
      • read-Befehl mit Optionen namens --delay, --fgcolor und --light-mode
      • add-Befehl mit Argumenten namens quote und byline
      • delete-Befehl mit einer Option namens --search-terms

* Eine globale Option ist für den Befehl, dem sie zugewiesen ist, und rekursiv für alle Unterbefehle verfügbar.

Hier sehen Sie eine Beispiel-Befehlszeileneingabe, die jeden der verfügbaren Befehle mit den zugehörigen Optionen und Argumenten aufruft:

scl quotes read --file sampleQuotes.txt --delay 40 --fgcolor red --light-mode
scl quotes add "Hello world!" "Nancy Davolio"
scl quotes delete --search-terms David "You can do" Antoine "Perfection is achieved"
  1. Ersetzen Sie in Program.cs den Code, der die --file-Option erstellt, durch den folgenden Code:

    var fileOption = new Option<FileInfo?>(
        name: "--file",
        description: "An option whose argument is parsed as a FileInfo",
        isDefault: true,
        parseArgument: result =>
        {
            if (result.Tokens.Count == 0)
            {
                return new FileInfo("sampleQuotes.txt");
    
            }
            string? filePath = result.Tokens.Single().Value;
            if (!File.Exists(filePath))
            {
                result.ErrorMessage = "File does not exist";
                return null;
            }
            else
            {
                return new FileInfo(filePath);
            }
        });
    

    Dieser Code verwendet ParseArgument<T>, um die benutzerdefinierte Analyse, Überprüfung und Fehlerbehandlung zu ermöglichen.

    Ohne diesen Code werden fehlende Dateien mit einer Ausnahme und Stapelüberwachung gemeldet. Mit diesem Code wird nur die angegebene Fehlermeldung angezeigt.

    Dieser Code gibt auch einen Standardwert an, weshalb isDefault auf true festgelegt wird. Wenn Sie isDefault nicht auf true festlegen, wird der parseArgument-Delegat nicht aufgerufen, wenn keine Eingabe für --file bereitgestellt wird.

  2. Fügen Sie nach dem Code, der lightModeOption erstellt, Optionen und Argumente für die Befehle add und delete hinzu:

    var searchTermsOption = new Option<string[]>(
        name: "--search-terms",
        description: "Strings to search for when deleting entries.")
        { IsRequired = true, AllowMultipleArgumentsPerToken = true };
    
    var quoteArgument = new Argument<string>(
        name: "quote",
        description: "Text of quote.");
    
    var bylineArgument = new Argument<string>(
        name: "byline",
        description: "Byline of quote.");
    

    Durch die AllowMultipleArgumentsPerToken-Einstellung können Sie den Optionsnamen --search-terms weglassen, wenn Sie Elemente in der Liste nach dem ersten angeben. Die folgenden Beispiele für Befehlszeileneingaben werden äquivalent:

    scl quotes delete --search-terms David "You can do"
    scl quotes delete --search-terms David --search-terms "You can do"
    
  3. Ersetzen Sie den Code, der den Stammbefehl und den read-Befehl erstellt, durch den folgenden Code:

    var rootCommand = new RootCommand("Sample app for System.CommandLine");
    rootCommand.AddGlobalOption(fileOption);
    
    var quotesCommand = new Command("quotes", "Work with a file that contains quotes.");
    rootCommand.AddCommand(quotesCommand);
    
    var readCommand = new Command("read", "Read and display the file.")
        {
            delayOption,
            fgcolorOption,
            lightModeOption
        };
    quotesCommand.AddCommand(readCommand);
    
    var deleteCommand = new Command("delete", "Delete lines from the file.");
    deleteCommand.AddOption(searchTermsOption);
    quotesCommand.AddCommand(deleteCommand);
    
    var addCommand = new Command("add", "Add an entry to the file.");
    addCommand.AddArgument(quoteArgument);
    addCommand.AddArgument(bylineArgument);
    addCommand.AddAlias("insert");
    quotesCommand.AddCommand(addCommand);
    

    Durch diesen Code werden folgende Änderungen vorgenommen:

    • Die --file-Option wird aus dem read-Befehl entfernt.

    • Die --file-Option wird dem Stammbefehl als globale Option hinzugefügt.

    • Ein quotes-Befehl wird erstellt und zum Stammbefehl hinzugefügt.

    • Der read-Befehl wird dem quotes-Befehl anstelle des Stammbefehls hinzugefügt.

    • Die Befehle add und delete werden erstellt und dem quotes-Befehl hinzugefügt.

    Das Ergebnis ist die folgende Befehlshierarchie:

    • Stammbefehl
      • quotes
        • read
        • add
        • delete

    Die App implementiert nun das empfohlene Muster, bei dem der übergeordnete Befehl (quotes) einen Bereich oder eine Gruppe angibt, und die untergeordneten Befehle (read, add, delete) sind Aktionen.

    Globale Optionen werden auf den Befehl und rekursiv auf Unterbefehle angewendet. Da sich die --file-Option im Stammbefehl befindet, wird sie automatisch in allen Unterbefehlen der App verfügbar sein.

  4. Fügen Sie nach dem SetHandler-Code neuen SetHandler-Code für die neuen Unterbefehle hinzu:

    deleteCommand.SetHandler((file, searchTerms) =>
        {
            DeleteFromFile(file!, searchTerms);
        },
        fileOption, searchTermsOption);
    
    addCommand.SetHandler((file, quote, byline) =>
        {
            AddToFile(file!, quote, byline);
        },
        fileOption, quoteArgument, bylineArgument);
    

    Der Unterbefehl quotes verfügt nicht über einen Handler, da es sich nicht um einen Leaf-Befehl handelt. Die Unterbefehle read, add und delete sind Leaf-Befehle unter quotes, und SetHandler wird für jeden aufgerufen.

  5. Fügen Sie die Handler für add und delete hinzu.

    internal static void DeleteFromFile(FileInfo file, string[] searchTerms)
    {
        Console.WriteLine("Deleting from file");
        File.WriteAllLines(
            file.FullName, File.ReadLines(file.FullName)
                .Where(line => searchTerms.All(s => !line.Contains(s))).ToList());
    }
    internal static void AddToFile(FileInfo file, string quote, string byline)
    {
        Console.WriteLine("Adding to file");
        using StreamWriter? writer = file.AppendText();
        writer.WriteLine($"{Environment.NewLine}{Environment.NewLine}{quote}");
        writer.WriteLine($"{Environment.NewLine}-{byline}");
        writer.Flush();
    }
    

Die fertige App sieht wie folgt aus:

using System.CommandLine;

namespace scl;

class Program
{
    static async Task<int> Main(string[] args)
    {
        var fileOption = new Option<FileInfo?>(
            name: "--file",
            description: "An option whose argument is parsed as a FileInfo",
            isDefault: true,
            parseArgument: result =>
            {
                if (result.Tokens.Count == 0)
                {
                    return new FileInfo("sampleQuotes.txt");

                }
                string? filePath = result.Tokens.Single().Value;
                if (!File.Exists(filePath))
                {
                    result.ErrorMessage = "File does not exist";
                    return null;
                }
                else
                {
                    return new FileInfo(filePath);
                }
            });

        var delayOption = new Option<int>(
            name: "--delay",
            description: "Delay between lines, specified as milliseconds per character in a line.",
            getDefaultValue: () => 42);

        var fgcolorOption = new Option<ConsoleColor>(
            name: "--fgcolor",
            description: "Foreground color of text displayed on the console.",
            getDefaultValue: () => ConsoleColor.White);

        var lightModeOption = new Option<bool>(
            name: "--light-mode",
            description: "Background color of text displayed on the console: default is black, light mode is white.");

        var searchTermsOption = new Option<string[]>(
            name: "--search-terms",
            description: "Strings to search for when deleting entries.")
            { IsRequired = true, AllowMultipleArgumentsPerToken = true };

        var quoteArgument = new Argument<string>(
            name: "quote",
            description: "Text of quote.");

        var bylineArgument = new Argument<string>(
            name: "byline",
            description: "Byline of quote.");

        var rootCommand = new RootCommand("Sample app for System.CommandLine");
        rootCommand.AddGlobalOption(fileOption);

        var quotesCommand = new Command("quotes", "Work with a file that contains quotes.");
        rootCommand.AddCommand(quotesCommand);

        var readCommand = new Command("read", "Read and display the file.")
            {
                delayOption,
                fgcolorOption,
                lightModeOption
            };
        quotesCommand.AddCommand(readCommand);

        var deleteCommand = new Command("delete", "Delete lines from the file.");
        deleteCommand.AddOption(searchTermsOption);
        quotesCommand.AddCommand(deleteCommand);

        var addCommand = new Command("add", "Add an entry to the file.");
        addCommand.AddArgument(quoteArgument);
        addCommand.AddArgument(bylineArgument);
        addCommand.AddAlias("insert");
        quotesCommand.AddCommand(addCommand);

        readCommand.SetHandler(async (file, delay, fgcolor, lightMode) =>
            {
                await ReadFile(file!, delay, fgcolor, lightMode);
            },
            fileOption, delayOption, fgcolorOption, lightModeOption);

        deleteCommand.SetHandler((file, searchTerms) =>
            {
                DeleteFromFile(file!, searchTerms);
            },
            fileOption, searchTermsOption);

        addCommand.SetHandler((file, quote, byline) =>
            {
                AddToFile(file!, quote, byline);
            },
            fileOption, quoteArgument, bylineArgument);

        return await rootCommand.InvokeAsync(args);
    }

    internal static async Task ReadFile(
                FileInfo file, int delay, ConsoleColor fgColor, bool lightMode)
    {
        Console.BackgroundColor = lightMode ? ConsoleColor.White : ConsoleColor.Black;
        Console.ForegroundColor = fgColor;
        var lines = File.ReadLines(file.FullName).ToList();
        foreach (string line in lines)
        {
            Console.WriteLine(line);
            await Task.Delay(delay * line.Length);
        };

    }
    internal static void DeleteFromFile(FileInfo file, string[] searchTerms)
    {
        Console.WriteLine("Deleting from file");
        File.WriteAllLines(
            file.FullName, File.ReadLines(file.FullName)
                .Where(line => searchTerms.All(s => !line.Contains(s))).ToList());
    }
    internal static void AddToFile(FileInfo file, string quote, string byline)
    {
        Console.WriteLine("Adding to file");
        using StreamWriter? writer = file.AppendText();
        writer.WriteLine($"{Environment.NewLine}{Environment.NewLine}{quote}");
        writer.WriteLine($"{Environment.NewLine}-{byline}");
        writer.Flush();
    }
}

Erstellen Sie das Projekt, und testen Sie dann die folgenden Befehle.

Übermitteln Sie mit dem read-Befehl eine nicht vorhandene Datei an --file, und Sie erhalten eine Fehlermeldung anstelle einer Ausnahme und Stapelüberwachung:

scl quotes read --file nofile
File does not exist

Versuchen Sie, den Unterbefehl quotes auszuführen, und Sie erhalten eine Meldung, die Sie anweist, read, add oder delete zu verwenden:

scl quotes
Required command was not provided.

Description:
  Work with a file that contains quotes.

Usage:
  scl quotes [command] [options]

Options:
  --file <file>   An option whose argument is parsed as a FileInfo [default: sampleQuotes.txt]
  -?, -h, --help  Show help and usage information

Commands:
  read                          Read and display the file.
  delete                        Delete lines from the file.
  add, insert <quote> <byline>  Add an entry to the file.

Führen Sie den Unterbefehl add aus, und sehen Sie sich dann das Ende der Textdatei an, um den hinzugefügten Text anzuzeigen:

scl quotes add "Hello world!" "Nancy Davolio"

Führen Sie den Unterbefehl delete mit Suchzeichenfolgen am Anfang der Datei aus, und sehen Sie sich dann den Anfang der Textdatei an, um zu sehen, wo Text entfernt wurde:

scl quotes delete --search-terms David "You can do" Antoine "Perfection is achieved"

Hinweis

Wenn die Ausführung im Ordner bin/debug/net6.0 erfolgt, finden Sie in diesem Ordner die Datei mit Änderungen über die Befehle add und delete. Die Kopie der Datei im Projektordner bleibt unverändert.

Nächste Schritte

In diesem Tutorial haben Sie eine einfache Befehlszeilen-App erstellt, die System.CommandLine verwendet. Weitere Informationen zur Bibliothek finden Sie unter Übersicht über System.CommandLine.