Sdílet prostřednictvím


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

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

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
    

    Nebo v .NET 10+:

    dotnet package add System.CommandLine
    

Parsování argumentů

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

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);
  • args Analyzuje a zkontroluje, jestli byla pro --file možnost zadaná nějaká hodnota. Pokud ano, volá metodu ReadFile pomocí parsované hodnoty a vrátí ukončovací kód 0:
ParseResult parseResult = rootCommand.Parse(args);
if (parseResult.Errors.Count == 0 && 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í kód 1:
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 otevřete příkazový řádek ve výstupní složce sestavení, aby se spustil 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"
    }
  }
}

Pokud ale požádáte o zobrazení nápovědy zadáním --help, nic se netiskne na konzoli. Je to proto, že aplikace zatím nezpracuje scénář, ve --file kterém není k dispozici, a neexistují žádné chyby analýzy.

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. Delegát akce přijímá parametr ParseResult a vrací ukončovací kód int. (K dispozici jsou také asynchronní akce ). Ukončovací kód je vrácen metodou ParseResult.Invoke(InvocationConfiguration) a lze jej použít k označení, zda byl příkaz úspěšně spuštěn nebo ne.

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.

Pokud se zobrazí výzva k zobrazení nápovědy zadáním 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 console

RootCommand ve výchozím nastavení poskytuje možnost nápovědy, možnost verze a direktivu Navrhnout. Metoda ParseResult.Invoke(InvocationConfiguration) je zodpovědná za vyvolání akce parsovaného symbolu. Může to být akce explicitně definovaná pro příkaz nebo akci nápovědy definovanou System.CommandLine pro System.CommandLine.Help.HelpOption.

Navíc když metoda Invoke zjistí případné chyby analýzy, vytiskne je na standardní chybový výstup, vytiskne nápovědu na standardní výstup a vrátí 1 jako 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 umožňují koncovému uživateli nakonfigurovat barvy textu 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ě ukázek dotnet do adresáře projektu.

    (Informace o tom, jak stáhnout soubory, najdete v pokynech v ukázkách a kurzech.)

  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 výstupní složky při vytváření 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

Pokud zadáte neplatnou hodnotu --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'.

Pokud zadáte neplatnou hodnotu --file, zobrazí se výjimka:

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:

Command Možnosti Arguments
Kořenový příkaz --file (rekurzivní)
quotes
read --delay, --fgcolor--light-mode
add quote a byline
delete --search-terms

( Rekurzivní možnost je k dispozici pro příkaz, ke kterému je přiřazená, 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á 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í Option<T>.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í 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

Pokud se pokusíte spustit dílčí příkaz quotes, 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:

Soubor ve výstupní složce odráží změny z příkazů add 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 System.CommandLine přehledu. Pokud chcete povolit možnosti dokončování tabulátoru, přečtěte si téma Dokončení tabulátoru pro System.CommandLine.