Создание CLI-приложений при помощи System.CommandLine в .NET

Создание CLI-приложений при помощи System.CommandLine в .NET Гайд, IT, Dotnet, Программирование, Гифка, Длиннопост

В .NET уже несколько лет существует библиотека System.CommandLine, позволяющая быстро создавать CLI-приложения. Несмотря на то, что библиотека ещё в стадии beta, её активно используют и сами разработчики Microsoft, например, в утилите dotnet из пакета .NET SDK.

Преимущества этой библиотеки в том, что она позволяет сосредоточиться на разработке полезного функционала приложения и не тратить время на создание парсера команд, опций и аргументов, а также имеет широкие возможности для кастомизации.

Реализация простого CLI-приложения

Библиотека поддерживает следующие виды токенов:

Создание CLI-приложений при помощи System.CommandLine в .NET Гайд, IT, Dotnet, Программирование, Гифка, Длиннопост

Опции и аргументы определяются совместно через обобщённый тип Option<T>:

Создание CLI-приложений при помощи System.CommandLine в .NET Гайд, IT, Dotnet, Программирование, Гифка, Длиннопост

Полностью исходный код можно найти в нашем GitLab-репозитории.

Subcommand и command отличаются тем, что subcommand определяет группу команд, а command определяет непосредственно действие, выполняемое командой.

Определим для начала команду sum:

Создание CLI-приложений при помощи System.CommandLine в .NET Гайд, IT, Dotnet, Программирование, Гифка, Длиннопост

Разделение на команды и группы команд очень условное, т.к. с точки зрения C# оба вида определяются через класс Command. Также нам ничто не мешает определить действие и для группы команд:

Создание CLI-приложений при помощи System.CommandLine в .NET Гайд, IT, Dotnet, Программирование, Гифка, Длиннопост

Помимо примитивных типов, библиотека также поддерживает массивы, списки, FileInfo, DirectoryInfo и другие. Полный список можно узнать, заглянув в документацию. Если есть необходимость привязать опции к кастомному типу, то можно воспользоваться встроенным механизмом привязки через тип BinderBase<T>. Определим операцию вычитания, используя этот способ:

Создание CLI-приложений при помощи System.CommandLine в .NET Гайд, IT, Dotnet, Программирование, Гифка, Длиннопост

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

Создание CLI-приложений при помощи System.CommandLine в .NET Гайд, IT, Dotnet, Программирование, Гифка, Длиннопост

Осталось определить Root command через одноимённый класс RootCommand :

Создание CLI-приложений при помощи System.CommandLine в .NET Гайд, IT, Dotnet, Программирование, Гифка, Длиннопост

Теперь можно собрать приложение и проверить работу:

Создание CLI-приложений при помощи System.CommandLine в .NET Гайд, IT, Dotnet, Программирование, Гифка, Длиннопост

Внедрение зависимостей

Жизненный цикл CLI-приложения выглядит следующим образом:

  1. Вызывается некоторая команда.

  2. Запускается процесс.

  3. Происходит обработка данных, возвращается результат.

  4. Процесс завершается.

Классические контейнеры зависимостей не рекомендуется использовать, поскольку зависимости одной команды могут быть совершенно не нужны для другой команды, а инициализация всех зависимостей может увеличить время запуска CLI-приложения. Вместо этого можно воспользоваться механизмом внедрения зависимостей для конкретного обработчика. Для этого снова понадобится класс BinderBase<T>. Определим новый класс ResultWriter, который будет записывать результат математической операции в файл:

Создание CLI-приложений при помощи System.CommandLine в .NET Гайд, IT, Dotnet, Программирование, Гифка, Длиннопост

Теперь создадим класс ResultWriterBinder. Этот класс инкапсулирует экземпляр ResultWriter:

Создание CLI-приложений при помощи System.CommandLine в .NET Гайд, IT, Dotnet, Программирование, Гифка, Длиннопост

=> _resultWriter;

Теперь определим операцию умножения и внедрим туда экземпляр ResultWriter:

Создание CLI-приложений при помощи System.CommandLine в .NET Гайд, IT, Dotnet, Программирование, Гифка, Длиннопост

Такой подход позволяет внедрять зависимости в обработчики команд независимо друг от друга.

Кастомизация вывода

Справка генерируется автоматически из описаний, которые использовались при инициализации опций и команд. Например, команда cli-app math sum -h отобразит следующее:

Создание CLI-приложений при помощи System.CommandLine в .NET Гайд, IT, Dotnet, Программирование, Гифка, Длиннопост

При желании можно заменить любой раздел справки, например, Description или создать новый. Добавим новую строку с текстом «This is a new section» в начало справки:

Создание CLI-приложений при помощи System.CommandLine в .NET Гайд, IT, Dotnet, Программирование, Гифка, Длиннопост

Тогда вывод станет следующим:

Создание CLI-приложений при помощи System.CommandLine в .NET Гайд, IT, Dotnet, Программирование, Гифка, Длиннопост

Если требуется улучшить внешний вид вывода данных в целом, то сделать это можно, например, написав кастомный способ отображения при помощи методов и свойств класса Console, таких как SetCursorPosition, ForegroundColor, BackgroundColor и т.д. Либо воспользоваться 3rd-party библиотеками:

1. ShellProgressBar. Простая библиотека для отображения прогресса в командном окне.

2. Spectre.Console. Мощная библиотека для создания красивых консольных приложений, которая имеет множество компонентов, упрощающих создание интерфейса. Кстати, обложка для статьи была сделана с помощью этой библиотеки.

3. ConsoleGUI. Позволяет создавать полноценный GUI на основе консоли. Судя по всему, автор вдохновлялся WPF, так как в ней содержатся привычные для этого фреймворка компоненты: TextBox, CheckBox, DataGrid, DockPanel и другие.

Заключение

Библиотека System.CommandLine является полезным инструментом для создания CLI-приложений. Она даёт разработчикам гибкий инструментарий для работы командами и опциями, что позволяет сократить время разработки и создать удобный и функциональный пользовательский интерфейс.

Лига программистов

1.6K постов11.5K подписчиков

Добавить пост

Правила сообщества

- Будьте взаимовежливы, аргументируйте критику

- Приветствуются любые посты по тематике программирования

- Если ваш пост содержит ссылки на внешние ресурсы - он должен быть самодостаточным. Вариации на тему "далее читайте в моей телеге" будут удаляться из сообщества