Kurz: Začínáme s System.CommandLine

Důležité

System.CommandLine je aktuálně ve verzi PREVIEW a tato dokumentace je určená pro verzi 2.0 beta 4. Některé informace se týkají předběžného vydání produktu, který může být před vydáním podstatně změněn. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.

V tomto kurzu se dozvíte, jak vytvořit aplikaci příkazového řádku .NET, která používá knihovnuSystem.CommandLine. Začnete vytvořením jednoduchého kořenového příkazu, který má jednu možnost. Pak do této základny přidáte složitější aplikaci, která bude obsahovat několik dílčích příkazů a různé možnosti pro každý příkaz.

V tomto kurzu se naučíte:

  • Umožňuje vytvářet příkazy, možnosti a argumenty.
  • Zadejte výchozí hodnoty pro možnosti.
  • Přiřaďte k příkazům možnosti a argumenty.
  • Přiřaďte možnost rekurzivně všem dílčím příkazům v rámci příkazu.
  • Práce s několika úrovněmi vnořených dílčích příkazů
  • Vytváření aliasů pro příkazy a možnosti
  • Práce s stringtypy možností , string[], int, boolFileInfo a výčtu
  • Vytvořte vazbu hodnot možností na kód obslužné rutiny příkazu.
  • Pro parsování a ověřování možností použijte vlastní kód.

Požadavky

Nebo

Vytvoření aplikace

Vytvořte projekt konzolové aplikace .NET 6 s názvem "scl".

  1. Vytvořte složku s názvem scl pro projekt a pak otevřete příkazový řádek v nové složce.

  2. Spusťte následující příkaz:

    dotnet new console --framework net6.0
    

Nainstalujte balíček System.CommandLine.

  • Spusťte následující příkaz:

    dotnet add package System.CommandLine --prerelease
    

    Možnost --prerelease je nezbytná, protože knihovna je stále v beta verzi.

  1. Obsah souboru Program.cs nahraďte tímto kódem:

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

Předchozí kód:

  • Vytvoří možnost typu --fileFileInfo a přiřadí ji ke kořenovému příkazu:

    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);
    
  • Určuje, že ReadFile se jedná o metodu, která bude volána při vyvolání kořenového příkazu:

    rootCommand.SetHandler((file) => 
        { 
            ReadFile(file!); 
        },
        fileOption);
    
  • Zobrazí obsah zadaného souboru při vyvolání kořenového příkazu:

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

Otestování aplikace

Při vývoji aplikace příkazového řádku můžete testovat libovolným z následujících způsobů:

  • dotnet build Spusťte příkaz a otevřete příkazový řádek ve složce scl/bin/Debug/net6.0 a spusťte spustitelný soubor:

    dotnet build
    cd bin/Debug/net6.0
    scl --file scl.runtimeconfig.json
    
  • Hodnoty možností použijte dotnet run a předejte do aplikace místo run do příkazu tak, že je zahrnete za --, jako v následujícím příkladu:

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

    V .NET 7.0.100 SDK Preview můžete použít commandLineArgs soubor launchSettings.json spuštěním příkazu dotnet run --launch-profile <profilename>.

  • Publikujte projekt do složky, otevřete v této složce příkazový řádek a spusťte spustitelný soubor:

    dotnet publish -o publish
    cd ./publish
    scl --file scl.runtimeconfig.json
    
  • V sadě Visual Studio 2022 vyberte z nabídky Ladit>vlastnosti ladění a zadejte možnosti a argumenty do pole Argumenty příkazového řádku . Například:

    Argumenty příkazového řádku v sadě Visual Studio 2022

    Pak aplikaci spusťte, například stisknutím kláves Ctrl+F5.

V tomto kurzu se předpokládá, že používáte první z těchto možností.

Když aplikaci spustíte, zobrazí se obsah souboru určený --file možností.

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

Výstup nápovědy

System.CommandLine automaticky poskytuje výstup nápovědy:

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

Výstup verze

System.CommandLine automaticky poskytuje výstup verze:

scl --version
1.0.0

Přidání podpříkazu a možností

V této části:

  • Vytvořte další možnosti.
  • Vytvořte podpříkaz.
  • Nové možnosti přiřaďte novému podpříkazu.

Nové možnosti vám umožní nakonfigurovat barvy textu na popředí a pozadí a rychlost čtení. Tyto funkce se použijí ke čtení kolekce uvozovek, které pocházejí z kurzu konzolové aplikace Teleprompter.

  1. Zkopírujte souborsampleQuotes.txt z úložiště GitHub pro tuto ukázku do adresáře projektu. Informace o tom, jak stahovat soubory, najdete v pokynech v části Ukázky a kurzy.

  2. Otevřete soubor projektu a přidejte <ItemGroup> prvek těsně před uzavírací </Project> značku:

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

    Přidání tohoto kódu způsobí zkopírování textového souboru do složky bin/debug/net6.0 při sestavování aplikace. Když tedy spustíte spustitelný soubor v této složce, můžete k souboru přistupovat podle názvu bez zadání cesty ke složce.

  3. V souboru Program.cs za kódem, který možnost vytvoří --file , vytvořte možnosti pro řízení rychlosti čtení a barev textu:

    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. Po řádku, který vytváří kořenový příkaz, odstraňte řádek, který k němu přidá --file možnost. Tady ho odebíráte, protože ho přidáte do nového podpříkazu.

    var rootCommand = new RootCommand("Sample app for System.CommandLine");
    //rootCommand.AddOption(fileOption);
    
  5. Za řádkem, který vytvoří kořenový příkaz, vytvořte read dílčí příkaz. Přidejte možnosti do tohoto podpříkazu a přidejte dílčí příkaz do kořenového příkazu.

    var readCommand = new Command("read", "Read and display the file.")
        {
            fileOption,
            delayOption,
            fgcolorOption,
            lightModeOption
        };
    rootCommand.AddCommand(readCommand);
    
  6. SetHandler Nahraďte kód následujícím SetHandler kódem pro nový podpříkaz:

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

    Už nevoláte SetHandler kořenový příkaz, protože kořenový příkaz už nepotřebuje obslužnou rutinu. Pokud má příkaz dílčí příkazy, obvykle musíte při vyvolání aplikace příkazového řádku zadat jeden z dílčích příkazů.

  7. Nahraďte metodu ReadFile obslužné rutiny následujícím kódem:

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

Aplikace teď vypadá takto:

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

Testování nového podpříkazu

Když se teď pokusíte aplikaci spustit bez zadání dílčího příkazu, zobrazí se chybová zpráva následovaná zprávou nápovědy, která určuje dílčí příkaz, který je k dispozici.

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.

Text nápovědy pro podpříkaz read ukazuje, že jsou k dispozici čtyři možnosti. Zobrazí platné hodnoty výčtu.

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

Spusťte podpříkaz read s určením --file pouze možnosti a získáte výchozí hodnoty pro další tři možnosti.

scl read --file sampleQuotes.txt

Výchozí zpoždění 42 milisekund na znak způsobuje zpomalení čtení. Můžete ho urychlit nastavením --delay na nižší číslo.

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

Barvy textu můžete nastavit pomocí a --fgcolor--light-mode :

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

Zadejte neplatnou hodnotu a --delay zobrazí se chybová zpráva:

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

Zadejte neplatnou hodnotu a --file zobrazí se výjimka:

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

Přidání dílčích příkazů a vlastního ověření

Tato část vytvoří konečnou verzi aplikace. Po dokončení bude mít aplikace následující příkazy a možnosti:

  • kořenový příkaz s globální* možností s názvem --file
    • Příkaz quotes
      • read příkaz s možnostmi s názvy --delay, --fgcolora --light-mode
      • add příkaz s argumenty s názvem quote a byline
      • delete command with option named --search-terms

* Globální možnost je k dispozici pro příkaz, ke kterému je přiřazený, a rekurzivně pro všechny jeho dílčí příkazy.

Tady je ukázkový vstup příkazového řádku, který vyvolá každý z dostupných příkazů s možnostmi a argumenty:

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. V souboru Program.cs nahraďte kód, který možnost vytvoří --file , následujícím kódem:

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

    Tento kód používá ParseArgument<T> k poskytování vlastní analýzy, ověřování a zpracování chyb.

    Bez tohoto kódu se chybějící soubory hlásí s výjimkou a trasování zásobníku. S tímto kódem se zobrazí pouze zadaná chybová zpráva.

    Tento kód také určuje výchozí hodnotu, a proto se nastaví isDefault na true. Pokud na hodnotu nenastavíte isDefaulttrue, parseArgument delegát se nezavolá, pokud není zadaný žádný vstup pro --file.

  2. Za kód, který vytvoří lightModeOption, přidejte možnosti a argumenty pro add příkazy a delete :

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

    Nastavení AllowMultipleArgumentsPerToken umožňuje vynechat --search-terms název možnosti při zadávání prvků v seznamu za prvním z nich. Následující příklady zadávání příkazového řádku jsou ekvivalentní:

    scl quotes delete --search-terms David "You can do"
    scl quotes delete --search-terms David --search-terms "You can do"
    
  3. Nahraďte kód, který vytvoří kořenový příkaz, a read příkaz následujícím kódem:

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

    Tento kód provede následující změny:

    • Odebere --file možnost z read příkazu.

    • --file Přidá možnost jako globální možnost do kořenového příkazu.

    • Vytvoří quotes příkaz a přidá ho do kořenového příkazu.

    • read Přidá příkaz do příkazu quotes místo do kořenového příkazu.

    • Vytvoří add příkazy a delete a přidá je do příkazu quotes .

    Výsledkem je následující hierarchie příkazů:

    • Kořenový příkaz
      • quotes
        • read
        • add
        • delete

    Aplikace teď implementuje doporučený vzor, kdy nadřazený příkaz (quotes) určuje oblast nebo skupinu a jeho podřízené příkazy (read, add, delete) jsou akce.

    Globální možnosti se použijí na příkaz a rekurzivně na dílčí příkazy. Vzhledem k tomu --file , že je v kořenovém příkazu, bude automaticky k dispozici ve všech dílčích příkazech aplikace.

  4. SetHandler Za kód přidejte nový SetHandler kód pro nové podpříkazy:

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

    Podpříkaz quotes nemá obslužnou rutinu, protože se nejedná o příkaz list. Podpříkazy read, adda delete jsou příkazy typu list v části quotesa SetHandler jsou voláné pro každou z nich.

  5. Přidejte obslužné rutiny pro add a delete.

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

Hotová aplikace vypadá takto:

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

Sestavte projekt a pak zkuste následující příkazy.

Pomocí příkazu odešlete neexistující soubor do --fileread a místo výjimky a trasování zásobníku se zobrazí chybová zpráva:

scl quotes read --file nofile
File does not exist

Zkuste spustit podpříkaz quotes a zobrazí se zpráva, která vás nasměruje k použití read, addnebo 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.

Spusťte podpříkaz adda podívejte se na konec textového souboru, abyste viděli přidaný text:

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

Spusťte podpříkaz delete s vyhledávacími řetězci od začátku souboru a pak se podívejte na začátek textového souboru, abyste zjistili, kde byl text odebrán:

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

Poznámka

Pokud používáte soubor ve složce bin/debug/net6.0 , najdete v této složce soubor se změnami z add příkazů a delete . Kopie souboru ve složce projektu zůstane beze změny.

Další kroky

V tomto kurzu jste vytvořili jednoduchou aplikaci příkazového řádku, která používá System.CommandLine. Další informace o knihovně najdete v přehleduSystem.CommandLine.