Sdílet prostřednictvím


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 beta verzi 2.0 5. Některé informace se týkají předběžné verze produktu, který může být podstatně změněn před vydáním. Společnost Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, pokud jde o informace uvedené zde.

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

V tomto kurzu se naučíte:

  • Vytváření příkazů, možností a argumentů
  • Zadejte výchozí hodnoty pro možnosti.
  • Přiřaďte příkazům možnosti a argumenty.
  • Přiřaďte možnost rekurzivně všem dílčím příkazům pod příkazem.
  • 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 string, typy možností string[], int, bool, FileInfo a typy výčtu.
  • Přečtěte hodnoty možností pro kód akce příkazu
  • K analýze a ověřování možností použijte vlastní kód.

Požadavky

Nebo

  • Visual Studio 2022 s nainstalovanou pracovní sadou pro vývoj desktopových aplikací .NET.

Vytvoření aplikace

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

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

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

    dotnet new console --framework net9.0
    

Instalace balíčku System.CommandLine

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

    dotnet add package System.CommandLine --prerelease
    

    Nebo v .NET 10+:

    dotnet package add System.CommandLine --prerelease
    

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

Parsování argumentů

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

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

Předchozí kód:

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);
  • Analyzuje args a kontroluje, zda byla pro volbu --file poskytnuta nějaká hodnota. Pokud ano, volá metodu ReadFile pomocí parsované hodnoty a vrátí ukončovací 0 kód:
ParseResult parseResult = rootCommand.Parse(args);
if (parseResult.GetValue(fileOption) is FileInfo parsedFile)
{
    ReadFile(parsedFile);
    return 0;
}
  • Pokud nebyla zadaná --filežádná hodnota, vytiskne dostupné chyby analýzy a vrátí ukončovací 1 kód:
foreach (ParseError parseError in parseResult.Errors)
{
    Console.Error.WriteLine(parseError.Message);
}
return 1;
  • Metoda ReadFile přečte zadaný soubor a zobrazí jeho obsah v konzole:
static void ReadFile(FileInfo file)
{
    foreach (string line in File.ReadLines(file.FullName))
    {
        Console.WriteLine(line);
    }
}

Otestování aplikace

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

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

    dotnet build
    cd bin/Debug/net9.0
    scl --file scl.runtimeconfig.json
    
  • Použijte dotnet run a předejte do aplikace hodnoty možností místo příkazu run tak, že je za --zahrnete, jak je znázorněno v následujícím příkladu:

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

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ý možností --file.

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

Co se ale stane, když požádáte o zobrazení nápovědy poskytnutím --help? Do konzoly se nic nevytiskne, protože aplikace zatím nezpracovává scénář, kdy --file není poskytnuto a nejsou žádné chyby při analýze.

Parsování argumentů a vyvolání funkce ParseResult

System.CommandLine umožňuje určit akci, která se vyvolá, když se daný symbol (příkaz, direktiva nebo možnost) úspěšně parsuje. Akce je delegát, který přijímá System.CommandLine.ParseResult parametr a vrací ukončovací int kód ( jsou k dispozici také asynchronní akce). Ukončovací kód je vrácen metodou System.CommandLine.Parsing.ParseResult.Invoke a lze jej použít k označení, zda byl příkaz úspěšně spuštěn nebo ne.

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

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

Předchozí kód:

  • Určuje, že ReadFile je metoda, která bude volána při vyvolání kořenového příkazu:

    rootCommand.SetAction(parseResult =>
    {
        FileInfo parsedFile = parseResult.GetValue(fileOption);
        ReadFile(parsedFile);
        return 0;
    });
    
  • Parsuje args a vyvolá výsledek:

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

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

Co se stane, když ji požádáte o zobrazení nápovědy poskytnutím --help?

scl --help

Vytiskne se následující výstup:

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

System.CommandLine.RootCommand ve výchozím nastavení poskytuje možnost nápovědy, verze a návrh direktivy. ParseResult.Invoke metoda je zodpovědná za vyvolání akce parsovaného symbolu. Může to být akce explicitně definovaná pro náš příkaz nebo akce nápovědy definovaná System.CommandLine pro System.CommandLine.Help.HelpOption. Když navíc zjistí případné chyby analýzy, vytiskne je do standardního chybového výstupu, vytiskne nápovědu do standardního výstupu a vrátí 1 ukončovací kód.

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

Přidejte podpříkaz a možnosti

V této části budete:

  • 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 citátů, pocházejících z tutoriálu konzolové aplikace Teleprompter.

  1. Zkopírujte soubor sampleQuotes.txt z úložiště GitHub pro tuto ukázku do adresáře projektu. Informace o tom, jak stáhnout soubory, naleznete v pokynech v Ukázky a Kurzy.

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

    <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/net9.0 při sestavování aplikace. Takže když 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 Program.csza kódem, který vytvoří možnost --file, vytvořte možnosti pro řízení rychlosti čtení a barvy textu:

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

  5. Po řádku, který vytvoří kořenový příkaz, vytvořte podpříkaz read. Přidejte do tohoto podpříkazu možnosti (pomocí syntaxe inicializátoru kolekce místo Options vlastnosti) a přidejte podpříkaz do kořenového příkazu.

    Command readCommand = new("read", "Read and display the file.")
    {
        fileOption,
        delayOption,
        fgcolorOption,
        lightModeOption
    };
    rootCommand.Subcommands.Add(readCommand);
    
  6. Nahraďte kód SetAction následujícím kódem SetAction nového podpříkazu:

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

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

  7. Nahraďte metodu ReadFile akce následujícím kódem:

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

Aplikace teď vypadá takto:

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

Otestujte nový podpříkaz

Když se teď pokusíte spustit aplikaci bez zadání podpříkazu, zobrazí se chybová zpráva následovaná zprávou nápovědy, která určuje dostupný podpříkaz.

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.

Text nápovědy pro podpříkazy read ukazuje, že jsou k dispozici čtyři možnosti. Zobrazuje 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 dílčí příkaz read s uvedením pouze možnosti --file, tím získáte výchozí hodnoty pro další tři možnosti.

scl read --file sampleQuotes.txt

Zpoždění 42 milisekund na znak ve výchozím nastavení způsobuje pomalou rychlost čtení. Můžete ho urychlit nastavením --delay na nižší číslo.

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

K nastavení barev textu můžete použít --fgcolor a --light-mode:

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

Zadejte neplatnou hodnotu pro --delay a 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 pro --file a získáte výjimku:

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''

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

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 rekurzivní* možností s názvem --file
    • příkaz quotes
      • příkaz read s možnostmi pojmenovanými --delay, --fgcolora --light-mode
      • příkaz add s argumenty pojmenovanými quote a byline
      • příkaz delete s možností s názvem --search-terms

* Rekurzivní možnost je k dispozici pro příkaz, ke kterému je přiřazena, a rekurzivně ke všem dílčím příkazům.

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

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

    Tento kód používá System.CommandLine.Parsing.ArgumentResult k poskytování vlastní analýzy, ověřování a zpracování chyb.

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

    Tento kód také určuje výchozí hodnotu, což je důvod, proč se nastaví DefaultValueFactory na vlastní metodu analýzy.

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

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

    Nastavení xref:System.CommandLine.Option.AllowMultipleArgumentsPerToken umožňuje vynechat název volby --search-terms při zadávání prvků v seznamu po prvním. Uvádí, že následující příklady vstupu příkazového řádku jsou rovnocenné:

    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 příkaz read následujícím kódem:

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

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

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

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

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

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

    • Vytvoří add a delete příkazy 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, ve kterém nadřazený příkaz (quotes) určuje oblast nebo skupinu a jeho podřízené příkazy (read, add, delete) jsou akce.

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

  4. Za SetAction kód přidejte nový SetAction kód pro nové dílčí příkazy:

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

    Podpříkaz quotes nemá akci, protože se nejedná o příkaz typu list. Dílčí příkazy read, adda delete jsou příkazy typu list pod quotesa SetAction se volá pro každý z nich.

  5. Přidejte akce pro add a 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}");
    }
    

Hotová aplikace vypadá takto:

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

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

Odešlete neexistující soubor do --file pomocí příkazu read 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 přesměruje na 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 pak se podívejte na konec textového souboru, abyste viděli přidaný text:

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

Spusťte dílčí pří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 složku bin/debug/net9.0 , najdete v této složce soubor se změnami z add příkazů a delete příkazů. 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 System.CommandLine přehledu.