Delen via


Zelfstudie: Aan de slag met System.CommandLine

Deze zelfstudie laat zien hoe u een .NET-opdrachtregel-app maakt die gebruikmaakt van de System.CommandLine bibliotheek. U begint met het maken van een eenvoudige hoofdopdracht met één optie. Vervolgens bouwt u op die basis en maakt u een complexere app met meerdere subopdrachten en verschillende opties voor elke opdracht.

In deze zelfstudie leert u het volgende:

  • Opdrachten, opties en argumenten maken.
  • Geef standaardwaarden op voor opties.
  • Opties en argumenten toewijzen aan opdrachten.
  • Wijs een optie recursief toe aan alle subopdrachten onder een opdracht.
  • Omgaan met meerdere niveaus van geneste subopdrachten.
  • Maak aliassen voor opdrachten en opties.
  • Werken met string, string[], int, bool, FileInfo en enumeratietypen.
  • Optiewaarden lezen in opdrachtactiecode.
  • Gebruik aangepaste code voor het parseren en valideren van opties.

Vereiste voorwaarden

Of

De app maken

Maak een .NET 9-console-app-project met de naam 'scl'.

  1. Maak een map met de naam scl voor het project en open vervolgens een opdrachtprompt in de nieuwe map.

  2. Voer de volgende opdracht uit:

    dotnet new console --framework net9.0
    

Het System.CommandLine-pakket installeren

  • Voer de volgende opdracht uit:

    dotnet add package System.CommandLine --prerelease
    

    Of in .NET 10+:

    dotnet package add System.CommandLine --prerelease
    

    De --prerelease optie is nodig omdat de bibliotheek nog in bèta is.

De argumenten parseren

  1. Vervang de inhoud van Program.cs door de volgende code:

    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.Errors.Count == 0 && 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);
            }
        }
    }
    

De voorgaande code:

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);
  • Parseert de args en controleert of er een waarde is opgegeven voor --file de optie. Zo ja, dan roept het de methode aan met behulp van geparseerde waarde ReadFile en retourneert 0 afsluitcode:
ParseResult parseResult = rootCommand.Parse(args);
if (parseResult.Errors.Count == 0 && parseResult.GetValue(fileOption) is FileInfo parsedFile)
{
    ReadFile(parsedFile);
    return 0;
}
  • Als er geen waarde is opgegeven voor --file, worden de beschikbare parseringsfouten afgedrukt en wordt de afsluitcode 1 geretourneerd.
foreach (ParseError parseError in parseResult.Errors)
{
    Console.Error.WriteLine(parseError.Message);
}
return 1;
  • De ReadFile methode leest het opgegeven bestand en geeft de inhoud ervan weer op de console:
static void ReadFile(FileInfo file)
{
    foreach (string line in File.ReadLines(file.FullName))
    {
        Console.WriteLine(line);
    }
}

De app testen

U kunt een van de volgende manieren gebruiken om te testen tijdens het ontwikkelen van een opdrachtregel-app:

  • Voer de dotnet build opdracht uit en open vervolgens een opdrachtprompt in de map scl/bin/Debug/net9.0 om het uitvoerbare bestand uit te voeren:

    dotnet build
    cd bin/Debug/net9.0
    scl --file scl.runtimeconfig.json
    
  • Gebruik dotnet run en geef optiewaarden door aan de app in plaats van aan de run opdracht door ze op te geven na --, zoals in het volgende voorbeeld:

    dotnet run -- --file bin/Debug/net9.0/scl.runtimeconfig.json
    

In deze zelfstudie wordt ervan uitgegaan dat u de eerste van deze opties gebruikt.

Wanneer u de app uitvoert, wordt de inhoud van het bestand weergegeven dat is opgegeven door de --file optie.

{
  "runtimeOptions": {
    "tfm": "net9.0",
    "framework": {
      "name": "Microsoft.NETCore.App",
      "version": "9.0.0"
    }
  }
}

Maar wat gebeurt er als je het vraagt om de helpfunctie weer te geven met behulp van --help? Er wordt niets afgedrukt naar de console, omdat de app het scenario waarin --file niet is opgegeven nog niet wordt verwerkt en er geen parseringsfouten zijn.

De argumenten parseren en ParseResult aanroepen

System.CommandLine hiermee kunt u een actie opgeven die wordt aangeroepen wanneer een bepaald symbool (opdracht, instructie of optie) wordt geparseerd. De actie is een gemachtigde die een System.CommandLine.ParseResult parameter neemt en een int afsluitcode retourneert (asynchrone acties zijn ook beschikbaar). De afsluitcode wordt geretourneerd door de System.CommandLine.Parsing.ParseResult.Invoke methode en kan worden gebruikt om aan te geven of de opdracht is uitgevoerd of niet.

  1. Vervang de inhoud van Program.cs door de volgende code:

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

De voorgaande code:

  • Hiermee geeft u op dat ReadFile dit de methode is die wordt aangeroepen wanneer de hoofdopdracht wordt aangeroepen:

    rootCommand.SetAction(parseResult =>
    {
        FileInfo parsedFile = parseResult.GetValue(fileOption);
        ReadFile(parsedFile);
        return 0;
    });
    
  • Parseert het args resultaat en roept het resultaat aan :

    ParseResult parseResult = rootCommand.Parse(args);
    return parseResult.Invoke();
    

Wanneer u de app uitvoert, wordt de inhoud van het bestand weergegeven dat is opgegeven door de --file optie.

Wat gebeurt er als u het vraagt om de hulp weer te geven door --help op te geven?

scl --help

De volgende uitvoer wordt weergegeven:

Description:
  Sample app for System.CommandLine

Usage:
  scl [options]

Options:
  -?, -h, --help  Show help and usage information
  --version       Show version information
  --file          The file to read and display on the conso

RootCommand Biedt standaard de Help-optie, versieoptie en suggestie-instructie. De ParseResult.Invoke(InvocationConfiguration) methode is verantwoordelijk voor het aanroepen van de actie van geparseerd symbool. Dit kan de actie zijn die expliciet is gedefinieerd voor de opdracht of de Help-actie die is gedefinieerd voor System.CommandLineSystem.CommandLine.Help.HelpOption. Bovendien worden, wanneer eventuele parseringsfouten worden gedetecteerd, deze afgedrukt naar de standaardfout, wordt de standaarduitvoer afgedrukt en wordt deze geretourneerd 1 als de afsluitcode:

scl --invalid bla
Unrecognized command or argument '--invalid'.
Unrecognized command or argument 'bla'.

Een subopdracht en opties toevoegen

In deze sectie gaat u het volgende doen:

  • Maak meer opties.
  • Maak een subopdracht.
  • Wijs de nieuwe opties toe aan de nieuwe subopdracht.

Met de nieuwe opties kunt u de voorgrond- en achtergrondtekstkleuren en de leessnelheid configureren. Deze functies worden gebruikt om een verzameling citaten te lezen die afkomstig zijn uit de handleiding van de Teleprompter-console-app.

  1. Kopieer het sampleQuotes.txt bestand uit de GitHub-opslagplaats voor dit voorbeeld naar uw projectmap. Zie de instructies in Voorbeelden en zelfstudies voor meer informatie over het downloaden van bestanden.

  2. Open het projectbestand en voeg een <ItemGroup> element toe vlak voor de afsluitende </Project> tag:

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

    Als u deze markering toevoegt, wordt het tekstbestand gekopieerd naar de map bin/debug/net9.0 wanneer u de app bouwt. Dus wanneer u het uitvoerbare bestand in die map uitvoert, kunt u het bestand op naam openen zonder een mappad op te geven.

  3. Maak in Program.cs, na de code die de --file optie maakt, opties om de leessnelheid en tekstkleuren te beheren:

    Option<int> delayOption = new("--delay")
    {
        Description = "Delay between lines, specified as milliseconds per character in a line.",
        DefaultValueFactory = parseResult => 42
    };
    Option<ConsoleColor> fgcolorOption = new("--fgcolor")
    {
        Description = "Foreground color of text displayed on the console.",
        DefaultValueFactory = parseResult => ConsoleColor.White
    };
    Option<bool> lightModeOption = new("--light-mode")
    {
        Description = "Background color of text displayed on the console: default is black, light mode is white."
    };
    
  4. Verwijder na de regel die de hoofdopdracht maakt de code waarmee de --file optie wordt toegevoegd. U verwijdert deze hier omdat u deze toevoegt aan een nieuwe subopdracht.

  5. Maak na de regel die de hoofdopdracht maakt een read subopdracht. Voeg de opties toe aan deze subopdracht (met behulp van de syntaxis van de initialisatiefunctie voor verzamelingen in plaats Options van eigenschap) en voeg de subopdracht toe aan de hoofdopdracht.

    Command readCommand = new("read", "Read and display the file.")
    {
        fileOption,
        delayOption,
        fgcolorOption,
        lightModeOption
    };
    rootCommand.Subcommands.Add(readCommand);
    
  6. Vervang de SetAction code door de volgende SetAction code voor de nieuwe subopdracht:

    readCommand.SetAction(parseResult => ReadFile(
        parseResult.GetValue(fileOption),
        parseResult.GetValue(delayOption),
        parseResult.GetValue(fgcolorOption),
        parseResult.GetValue(lightModeOption)));
    

    U roept niet langer SetAction aan op de root-opdracht omdat de root-opdracht geen actie meer vereist. Wanneer een opdracht subopdrachten bevat, moet u doorgaans een van de subopdrachten opgeven bij het aanroepen van een opdrachtregel-app.

  7. Vervang de ReadFile actiemethode door de volgende code:

    internal static void ReadFile(FileInfo file, int delay, ConsoleColor fgColor, bool lightMode)
    {
        Console.BackgroundColor = lightMode ? ConsoleColor.White : ConsoleColor.Black;
        Console.ForegroundColor = fgColor;
        foreach (string line in File.ReadLines(file.FullName))
        {
            Console.WriteLine(line);
            Thread.Sleep(TimeSpan.FromMilliseconds(delay * line.Length));
        }
    }
    

De app ziet er nu als volgt uit:

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

        Option<int> delayOption = new("--delay")
        {
            Description = "Delay between lines, specified as milliseconds per character in a line.",
            DefaultValueFactory = parseResult => 42
        };
        Option<ConsoleColor> fgcolorOption = new("--fgcolor")
        {
            Description = "Foreground color of text displayed on the console.",
            DefaultValueFactory = parseResult => ConsoleColor.White
        };
        Option<bool> lightModeOption = new("--light-mode")
        {
            Description = "Background color of text displayed on the console: default is black, light mode is white."
        };

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

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

        readCommand.SetAction(parseResult => ReadFile(
            parseResult.GetValue(fileOption),
            parseResult.GetValue(delayOption),
            parseResult.GetValue(fgcolorOption),
            parseResult.GetValue(lightModeOption)));

        return rootCommand.Parse(args).Invoke();
    }

    internal static void ReadFile(FileInfo file, int delay, ConsoleColor fgColor, bool lightMode)
    {
        Console.BackgroundColor = lightMode ? ConsoleColor.White : ConsoleColor.Black;
        Console.ForegroundColor = fgColor;
        foreach (string line in File.ReadLines(file.FullName))
        {
            Console.WriteLine(line);
            Thread.Sleep(TimeSpan.FromMilliseconds(delay * line.Length));
        }
    }
}

De nieuwe subopdracht testen

Als u de app probeert uit te voeren zonder de subopdracht op te geven, wordt er een foutbericht weergegeven, gevolgd door een Help-bericht waarin de subopdracht wordt opgegeven die beschikbaar is.

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:
  -?, -h, --help  Show help and usage information
  --version       Show version information

Commands:
  read  Read and display the file.

In de Help-tekst voor subopdracht read ziet u dat er vier opties beschikbaar zijn. Er worden geldige waarden voor de opsomming weergegeven.

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

Voer een subopdracht read uit die alleen de --file optie opgeeft en u krijgt de standaardwaarden voor de andere drie opties.

scl read --file sampleQuotes.txt

De standaardvertraging van 42 milliseconden per teken zorgt voor een trage leessnelheid. U kunt dit versnellen door een lager getal in te stellen --delay .

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

U kunt --fgcolor en --light-mode gebruiken om tekstkleuren in te stellen.

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

Geef een ongeldige waarde op voor --delay en u krijgt een foutbericht:

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

Geef een ongeldige waarde op voor --file en u krijgt een uitzondering:

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

Subopdrachten en aangepaste validatie toevoegen

In deze sectie wordt de definitieve versie van de app gemaakt. Wanneer u klaar bent, beschikt de app over de volgende opdrachten en opties:

  • hoofdopdracht met een recursieve* optie met de naam --file
    • quotes bevelen
      • read opdracht met opties met de naam --delay, --fgcoloren --light-mode
      • add opdracht met argumenten met de naam quote en byline
      • delete opdracht met optie met de naam --search-terms

* Er is een recursieve optie beschikbaar voor de opdracht waaraan deze is toegewezen en recursief aan alle bijbehorende subopdrachten.

Hier ziet u voorbeeld van opdrachtregelinvoer die elk van de beschikbare opdrachten aanroept met de bijbehorende opties en argumenten:

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. Vervang in Program.cs de code waarmee de --file optie wordt gemaakt door de volgende code:

    Option<FileInfo> fileOption = new("--file")
    {
        Description = "An option whose argument is parsed as a FileInfo",
        Required = true,
        DefaultValueFactory = result =>
        {
            if (result.Tokens.Count == 0)
            {
                return new FileInfo("sampleQuotes.txt");
    
            }
            string filePath = result.Tokens.Single().Value;
            if (!File.Exists(filePath))
            {
                result.AddError("File does not exist");
                return null;
            }
            else
            {
                return new FileInfo(filePath);
            }
        }
    };
    

    Deze code maakt gebruik System.CommandLine.Parsing.ArgumentResult van aangepaste parsering, validatie en foutafhandeling.

    Zonder deze code worden ontbrekende bestanden met een uitzondering en stack trace gerapporteerd. Met deze code wordt alleen het opgegeven foutbericht weergegeven.

    Deze code specificeert ook een standaardwaarde, wat de reden is dat DefaultValueFactory wordt ingesteld op een aangepaste parseringsmethode.

  2. Voeg na de code die lightModeOption creëert, opties en argumenten toe voor de add en delete commando's.

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

    Met xref:System.CommandLine.Option.AllowMultipleArgumentsPerToken de instelling kunt u de --search-terms optienaam weglaten bij het opgeven van elementen in de lijst na de eerste. Dit maakt de volgende voorbeelden van opdrachtregelinvoerequivalent:

    scl quotes delete --search-terms David "You can do"
    scl quotes delete --search-terms David --search-terms "You can do"
    
  3. Vervang de code waarmee de hoofdopdracht en de read opdracht worden gemaakt door de volgende code:

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

    Met deze code worden de volgende wijzigingen aangebracht:

    • Hiermee verwijdert u de --file optie uit de read opdracht.

    • Hiermee voegt u de --file optie toe als recursieve optie aan de hoofdopdracht.

    • Hiermee maakt u een quotes opdracht en voegt u deze toe aan de hoofdopdracht.

    • Hiermee voegt u de read opdracht toe aan de quotes opdracht in plaats van aan de hoofdopdracht.

    • Hiermee maakt add en delete opdrachten en voegt ze toe aan de quotes opdracht.

    Het resultaat is de volgende opdrachthiërarchie:

    • Hoofdopdracht
      • quotes
        • read
        • add
        • delete

    De app implementeert nu het aanbevolen patroon waarbij de bovenliggende opdracht (quotes) een gebied of groep opgeeft en de onderliggende opdrachten (read, add, delete) acties zijn.

    Recursieve opties worden toegepast op de opdracht en recursief op subopdrachten. Omdat --file deze zich in de hoofdopdracht bevindt, is deze automatisch beschikbaar in alle subopdrachten van de app.

  4. Voeg na de SetAction code nieuwe SetAction code toe voor de nieuwe subopdrachten:

    deleteCommand.SetAction(parseResult => DeleteFromFile(
        parseResult.GetValue(fileOption),
        parseResult.GetValue(searchTermsOption)));
    
    addCommand.SetAction(parseResult => AddToFile(
        parseResult.GetValue(fileOption),
        parseResult.GetValue(quoteArgument),
        parseResult.GetValue(bylineArgument))
        );
    

    Subopdracht quotes heeft geen actie omdat het geen leaf-opdracht is. Subopdrachten read, adden delete zijn leaf-opdrachten onder quotes, en SetAction worden aangeroepen voor elk van deze opdrachten.

  5. Voeg de acties voor add en delete.

    internal static void DeleteFromFile(FileInfo file, string[] searchTerms)
    {
        Console.WriteLine("Deleting from file");
    
        var lines = File.ReadLines(file.FullName).Where(line => searchTerms.All(s => !line.Contains(s)));
        File.WriteAllLines(file.FullName, lines);
    }
    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}");
    }
    

De voltooide app ziet er als volgt uit:

using System.CommandLine;

namespace scl;

class Program
{
    static int Main(string[] args)
    {
        Option<FileInfo> fileOption = new("--file")
        {
            Description = "An option whose argument is parsed as a FileInfo",
            Required = true,
            DefaultValueFactory = result =>
            {
                if (result.Tokens.Count == 0)
                {
                    return new FileInfo("sampleQuotes.txt");

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

        Option<int> delayOption = new("--delay")
        {
            Description = "Delay between lines, specified as milliseconds per character in a line.",
            DefaultValueFactory = parseResult => 42
        };
        Option<ConsoleColor> fgcolorOption = new("--fgcolor")
        {
            Description = "Foreground color of text displayed on the console.",
            DefaultValueFactory = parseResult => ConsoleColor.White
        };
        Option<bool> lightModeOption = new("--light-mode")
        {
            Description = "Background color of text displayed on the console: default is black, light mode is white."
        };

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

        RootCommand rootCommand = new("Sample app for System.CommandLine");
        fileOption.Recursive = true;
        rootCommand.Options.Add(fileOption);

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

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

        Command deleteCommand = new("delete", "Delete lines from the file.");
        deleteCommand.Options.Add(searchTermsOption);
        quotesCommand.Subcommands.Add(deleteCommand);

        Command addCommand = new("add", "Add an entry to the file.");
        addCommand.Arguments.Add(quoteArgument);
        addCommand.Arguments.Add(bylineArgument);
        addCommand.Aliases.Add("insert");
        quotesCommand.Subcommands.Add(addCommand);

        readCommand.SetAction(parseResult => ReadFile(
            parseResult.GetValue(fileOption),
            parseResult.GetValue(delayOption),
            parseResult.GetValue(fgcolorOption),
            parseResult.GetValue(lightModeOption)));

        deleteCommand.SetAction(parseResult => DeleteFromFile(
            parseResult.GetValue(fileOption),
            parseResult.GetValue(searchTermsOption)));

        addCommand.SetAction(parseResult => AddToFile(
            parseResult.GetValue(fileOption),
            parseResult.GetValue(quoteArgument),
            parseResult.GetValue(bylineArgument))
            );

        return rootCommand.Parse(args).Invoke();
    }

    internal static void ReadFile(FileInfo file, int delay, ConsoleColor fgColor, bool lightMode)
    {
        Console.BackgroundColor = lightMode ? ConsoleColor.White : ConsoleColor.Black;
        Console.ForegroundColor = fgColor;
        foreach (string line in File.ReadLines(file.FullName))
        {
            Console.WriteLine(line);
            Thread.Sleep(TimeSpan.FromMilliseconds(delay * line.Length));
        }
    }
    internal static void DeleteFromFile(FileInfo file, string[] searchTerms)
    {
        Console.WriteLine("Deleting from file");

        var lines = File.ReadLines(file.FullName).Where(line => searchTerms.All(s => !line.Contains(s)));
        File.WriteAllLines(file.FullName, lines);
    }
    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}");
    }
}

Bouw het project, en voer daarna de volgende opdrachten uit.

Verzend een niet-bestaand bestand naar --file met de read opdracht en u krijgt een foutmelding in plaats van een exceptie en stack-trace:

scl quotes read --file nofile
File does not exist

Probeer de subopdracht quotes uit te voeren en u krijgt een bericht waarin u wordt verwezen naar het gebruik van read, add, of delete.

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.

Voer de subopdracht adduit en kijk vervolgens naar het einde van het tekstbestand om de toegevoegde tekst weer te geven:

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

Voer een subopdracht delete uit met zoekreeksen vanaf het begin van het bestand en kijk vervolgens naar het begin van het tekstbestand om te zien waar tekst is verwijderd:

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

Notitie

Als u in de de map bin/debug/net9.0 werkt, vindt u het bestand met wijzigingen van de add en delete opdrachten. De kopie van het bestand in de projectmap blijft ongewijzigd.

Volgende stappen

In deze zelfstudie hebt u een eenvoudige opdrachtregel-app gemaakt die gebruikmaakt van System.CommandLine. Zie System.CommandLine het overzicht voor meer informatie over de bibliotheek.