Поделиться через


Руководство. Начало работы с System.CommandLine

Это важно

System.CommandLine в настоящее время находится в предварительной версии, и эта документация предназначена для версии 2.0 бета-версии 5. Некоторые сведения относятся к предварительному выпуску продукта, который может быть существенно изменен до его выпуска. Корпорация Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых в отношении информации, предоставленной здесь.

В этом руководстве показано, как создать приложение командной строки .NET, использующее библиотеку System.CommandLine. Сначала вы создадите простую корневую команду, которая имеет один вариант. Затем вы создадите более сложное приложение, содержащее несколько вложенных команд и различные параметры для каждой команды.

В этом руководстве описано, как:

  • Создание команд, параметров и аргументов.
  • Укажите значения по умолчанию для параметров.
  • Назначение параметров и аргументов командам.
  • Назначьте опцию рекурсивно всем подкомандам под командой.
  • Работа с несколькими уровнями вложенных подкоманд.
  • Создайте псевдонимы для команд и параметров.
  • Работа с типами string, string[], int, bool, FileInfo и перечисления.
  • Чтение значений опций в коде выполнения команды.
  • Используйте пользовательский код для анализа и проверки параметров.

Предпосылки

Или

  • Visual Studio 2022 с установленным компонентом разработки десктопных приложений .NET.

Создание приложения

Создайте проект консольного приложения .NET 9 с именем SCL.

  1. Создайте папку с именем scl для проекта, а затем откройте командную строку в новой папке.

  2. Выполните следующую команду:

    dotnet new console --framework net9.0
    

Установка пакета System.CommandLine

  • Выполните следующую команду:

    dotnet add package System.CommandLine --prerelease
    

    Или в .NET 10+:

    dotnet package add System.CommandLine --prerelease
    

    Параметр --prerelease необходим, так как библиотека по-прежнему находится в бета-версии.

Анализ аргументов

  1. Замените содержимое файла Program.cs кодом, приведенным ниже.

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

Предыдущий код:

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, и проверяет, было ли указано какое-либо значение для параметра --file. В этом случае вызывается метод ReadFile, используя разобранное значение, и возвращает код выхода 0.
ParseResult parseResult = rootCommand.Parse(args);
if (parseResult.GetValue(fileOption) is FileInfo parsedFile)
{
    ReadFile(parsedFile);
    return 0;
}
  • Если для --file не было указано значение, он выводит доступные ошибки синтаксического анализа и возвращает 1 код выхода:
foreach (ParseError parseError in parseResult.Errors)
{
    Console.Error.WriteLine(parseError.Message);
}
return 1;
  • Метод ReadFile считывает указанный файл и отображает его содержимое в консоли:
static void ReadFile(FileInfo file)
{
    foreach (string line in File.ReadLines(file.FullName))
    {
        Console.WriteLine(line);
    }
}

Тестирование приложения

При разработке приложения командной строки вы можете использовать один из следующих способов для тестирования:

  • dotnet build Выполните команду, а затем откройте командную строку в папке scl/bin/Debug/net9.0, чтобы запустить исполняемый файл:

    dotnet build
    cd bin/Debug/net9.0
    scl --file scl.runtimeconfig.json
    
  • Используйте dotnet run и передайте значения параметров в приложение вместо команды run, включив их после --, как показано в следующем примере:

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

В этом руководстве предполагается, что вы используете первый из этих вариантов.

При запуске приложения отображается содержимое файла, указанного параметром --file.

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

Но что произойдет, если вы попросите систему отобразить справку, предоставив --help? Ничего не выводится в консоль, так как приложение пока не обрабатывает сценарий, в котором --file не указано, и ошибки синтаксического анализа отсутствуют.

Анализ аргументов и вызов parseResult

System.CommandLine позволяет указать действие, вызываемое при успешном анализе заданного символа (команды, директивы или параметра). Действие — это делегат, который принимает System.CommandLine.ParseResult параметр и возвращает int код выхода (асинхронные действия также доступны). Код выхода возвращается методом System.CommandLine.Parsing.ParseResult.Invoke и может использоваться для указания того, выполнена ли команда успешно или нет.

  1. Замените содержимое файла Program.cs кодом, приведенным ниже.

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

Предыдущий код:

  • Указывает, что ReadFile это метод, который будет вызываться при вызове корневой команды:

    rootCommand.SetAction(parseResult =>
    {
        FileInfo parsedFile = parseResult.GetValue(fileOption);
        ReadFile(parsedFile);
        return 0;
    });
    
  • args Анализирует результат и вызывает результат:

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

При запуске приложения отображается содержимое файла, указанного параметром --file.

Что произойдет, если вы попросите его отобразить справку, предоставив --help?

scl --help

Следующие выходные данные печатаются:

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 по умолчанию предоставляет параметр справки, параметр версии и директиву "Предложить". ParseResult.Invoke Метод отвечает за вызов действия обработанного символа. Это может быть действие, явно предназначенное для нашей команды, или действие, предназначенное для помощи и определенное System.CommandLine для System.CommandLine.Help.HelpOption. Кроме того, при обнаружении ошибок синтаксического анализа он выводит их в стандартную ошибку, печатает стандартные выходные данные и возвращает 1 код выхода:

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

Добавление подкоманда и параметров

В этом разделе вы:

  • Создайте дополнительные параметры.
  • Создайте подкоманда.
  • Назначьте новые параметры новой подкоманде.

Новые параметры позволяют настроить цвета переднего плана и фона текста и скорость чтения. Эти возможности будут использоваться для чтения коллекции цитат, поступающих из руководства консольного приложения телеcуфлера.

  1. Скопируйте файл sampleQuotes.txt из репозитория GitHub для этого примера в каталог проекта. Сведения о том, как скачать файлы, см. в инструкциях Samples and Tutorials.

  2. Откройте файл проекта и добавьте элемент <ItemGroup> непосредственно перед закрывающим тегом </Project>:

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

    Добавление этой разметки приводит к копированию текстового файла в папку bin/debug/net9.0 при сборке приложения. Таким образом, при запуске исполняемого файла в этой папке можно получить доступ к файлу по имени, не указывая путь к папке.

  3. В Program.csпосле кода, создающего параметр --file, создайте параметры для управления скоростью чтения и цветами текста:

    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. После строки, которая создает корневую команду, удалите код, который добавляет параметр --file к ней. Вы удаляете его здесь, поскольку добавите его в новую подкоманду.

  5. После строки, создающей корневую команду, создайте подкоманду read. Добавьте параметры в эту подкоманду (с помощью синтаксиса инициализатора коллекции, а не свойства Options) и добавьте подкоманду в корневую команду.

    Command readCommand = new("read", "Read and display the file.")
    {
        fileOption,
        delayOption,
        fgcolorOption,
        lightModeOption
    };
    rootCommand.Subcommands.Add(readCommand);
    
  6. Замените код SetAction следующим кодом SetAction для нового подкоманда:

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

    Вы больше не вызываете SetAction в корневой команде, потому что корневая команда больше не нуждается в действии. При наличии вложенных команд обычно необходимо указать один из вложенных команд при вызове приложения командной строки.

  7. Замените ReadFile метод действия следующим кодом:

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

Теперь приложение выглядит следующим образом:

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

Протестируйте новую подкоманду

Теперь, если вы пытаетесь запустить приложение без указания подкоманда, появится сообщение об ошибке, за которым следует сообщение справки, указывающее доступную подкоманда.

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.

Текст справки для субкоманда read показывает, что доступны четыре варианта. Отображаются допустимые значения для перечисления.

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

Запустите подкоманда read, указав только параметр --file, и вы получите значения по умолчанию для других трех параметров.

scl read --file sampleQuotes.txt

Задержка по умолчанию в 42 миллисекундах для каждого символа приводит к медленной скорости чтения. Вы можете ускорить его, установив --delay на более низкое число.

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

Для задания цветов текста можно использовать --fgcolor и --light-mode:

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

Укажите недопустимое значение для --delay и вы получите сообщение об ошибке:

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

Укажите недопустимое значение для --file и вы получите исключение:

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

Добавление подкоманд и настраиваемой проверки

В этом разделе создается окончательная версия приложения. По завершении приложение будет иметь следующие команды и параметры:

  • корневая команда с рекурсивным параметром, именуемым --file
    • команда quotes
      • команда read с параметрами с именем --delay, --fgcolorи --light-mode
      • команда add с аргументами с именем quote и byline
      • команда delete с параметром с именем --search-terms

* Рекурсивный параметр доступен команде, которой он назначен, и рекурсивно всем её подкомандам.

Ниже приведен пример входных данных командной строки, который вызывает каждую из доступных команд со своими параметрами и аргументами:

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. В Program.csзамените код, который создает параметр --file следующим кодом:

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

    Этот код использует System.CommandLine.Parsing.ArgumentResult для предоставления пользовательского синтаксического анализа, проверки и обработки ошибок.

    Без этого кода отсутствие файлов сообщается с вызовом исключения и трассировкой стека. В этом коде отображается только указанное сообщение об ошибке.

    Этот код также задает значение по умолчанию, поэтому DefaultValueFactory устанавливается на пользовательский метод синтаксического анализа.

  2. После кода, создающего lightModeOption, добавьте параметры и аргументы для команд add и 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."
    };
    

    Параметр xref:System.CommandLine.Option.AllowMultipleArgumentsPerToken позволяет опустить имя параметра --search-terms при указании элементов в списке после первого. В нем приведены следующие примеры эквивалента входных данных командной строки:

    scl quotes delete --search-terms David "You can do"
    scl quotes delete --search-terms David --search-terms "You can do"
    
  3. Замените код, который создает корневую команду и команду read следующим кодом:

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

    Этот код вносит следующие изменения:

    • Удаляет параметр --file из команды read.

    • Добавляет параметр --file в качестве рекурсивной опции к корневой команде.

    • Создает команду quotes и добавляет ее в корневую команду.

    • Добавляет команду read в команду quotes вместо корневой команды.

    • Создает команды add и delete и добавляет их в команду quotes.

    Результатом является следующая иерархия команд:

    • Корневая команда
      • quotes
        • read
        • add
        • delete

    Теперь приложение реализует рекомендуемый шаблон, в котором родительская команда (quotes) указывает область или группу, а его дочерние команды (read, add, delete) являются действиями.

    Рекурсивные параметры применяются к команде и рекурсивно к подкомандам. Так как --file находится в корневой команде, она будет доступна автоматически во всех подкомандах приложения.

  4. После кода SetAction добавьте новый код SetAction для новых подкоманд.

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

    Подкоманда quotes не имеет действия, поскольку это не команда-узел. Подкоманды read, addи delete являются конечными командами под quotes, и для каждой из них вызывается SetAction.

  5. Добавьте действия для add и 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}");
    }
    

Готовое приложение выглядит следующим образом:

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

Выполните сборку проекта, а затем выполните следующие команды.

Отправьте несуществующий файл в --file с помощью команды read, и вы получите сообщение об ошибке вместо исключения и трассировки стека:

scl quotes read --file nofile
File does not exist

Попробуйте запустить подкоманда quotes, и вы получите сообщение, которое направляет вас на использование read, addили 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.

Запустите подкоманда add, а затем просмотрите конец текстового файла, чтобы увидеть добавленный текст:

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

Запустите подкоманда delete со строками поиска с начала файла, а затем просмотрите начало текстового файла, чтобы узнать, где был удален текст:

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

Примечание.

Если вы работаете в папке bin/debug/net9.0 , в этой папке будет находиться файл с изменениями из add и delete команд. Копия файла в папке проекта остается неизменной.

Дальнейшие действия

В этом руководстве вы создали простое приложение командной строки, использующее System.CommandLine. Дополнительные сведения о библиотеке см. в System.CommandLine обзоре.