Сегодня мы собираемся показать вам, как начать парсинг аргументов командной строки. Кстати, это один пост из серии статей о .NET 5. У нас есть еще много интересного.
Приложения командной строки, также известные как консольные приложения, - это программы, созданные для использования из оболочки, например cmd или bash. Они существуют с 1960-х годов, задолго до появления Windows, MacOS или любого другого графического пользовательского интерфейса (GUI).
Обычно, когда вы начинаете изучать язык программирования, самый простой и распространенный стартовый пример -- это приложение Hello world. Подобные примеры в основном выводят на консоль только текст «Hello world», используя свои встроенные API. Компьютерное ПО может делать много разных вещей. Иногда у вас будет ввод, который каким-то образом преобразуется в вывод. В нашем примере «Hello world» нет никакого ввода.
Возьмем C#/.Net. Каждый раз, когда вы создаете новое консольное приложение, вы начинаете с файла Program.cs со статическим методом Main, который является точкой входа в ваше приложение:
...
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
...
Очень важной частью этого кода является определение аргумента string[] args. Это определение параметра, которое содержит все аргументы, которые передаются нашему исполняемому файлу во время инициализации нашего процесса. В отличие от C и C++, имя программы не рассматривается как первый аргумент командной строки в массиве args. Если вам нужно это значение, вы можете вызвать Environment.GetCommandLineArgs().
Если вы привыкли к приложениям командной строки, передача аргументов другим приложениям - очень распространенная задача. Да, вы можете вручную проанализировать эти значения, но если у вас есть несколько параметров, это может быть очень подверженным ошибкам кодом (который в любом случае в основном является шаблонным). Это похоже на проблему, которую кто-то уже мог исправить, не так ли? Поэтому, конечно, мы можем найти библиотеку NuGet, которая поможет нам проанализировать эти аргументы. В этой статье я сосредоточусь на CommandLineParser.
CommandLineParser
CommandLineParser - это библиотека с открытым исходным кодом, созданная Эриком Ньютоном и членами сообщества .NET. Она существует с 2005 года и её скачали более 26 миллионов раз! CommandLineParser «предлагает приложениям CLR простой и лаконичный API для управления аргументами командной строки и связанными задачами, такими как определение переключателей, параметров и команд».
Вместо ручного парсинга массива строк args вы можете просто определить класс, который будет парситься для вас библиотекой на основе набора атрибутов, с которыми вы аннотируете класс.
Вместо того, чтобы создавать еще один пример только для демонстрации этой библиотеки, я буду использовать консольное приложение WinML .NET5, которым я поделился в своем предыдущем посте. Вот исходный код. Начнем с этого и добавим NuGet-пакет CommandLineParser:
Давайте создадим новый класс с именем CommandLineOptions:
using CommandLine;
namespace ImageClassifier
{
public class CommandLineOptions
{
[Value(index: 0, Required = true, HelpText = "Путь к файлу изображения для анализа.")]
public string Path { get; set; }
[Option(shortName: 'c', longName: "confidence", Required = false, HelpText = "Minimum confidence.", Default = 0.9f)]
public float Confidence { get; set; }
}
}
Это почти все, что нам нужно для использования этой библиотеки. ValueAttribute и OptionAttribute предоставляются пакетом. Я использую именованные параметры, чтобы было ясно, для чего нужен каждый аргумент. Вернемся к нашему методу Program.cs Main, добавим оператор using, чтобы иметь возможность легко использовать классы пакета в этом файле:
using CommandLine;
Давайте изменим тип возвращаемого значения нашего метода Main на Task. Это означает, что любое возвращаемое нами значение int будет возвращено вызывающей стороне нашего процесса, что обычно указывает на успех/неудачу. В этом примере мы просто вернем 0 в случае успеха и любое другое значение, кроме 0, в случае ошибки:
static async Task Main(string[] args)
{
return await Parser.Default.ParseArguments<CommandLineOptions>(args)
.MapResult(async (CommandLineOptions opts) =>
{
try
{
// У нас есть полученные аргументы, поэтому давайте просто передадим их
return await AnalyzeFileAsync(opts.Path, opts.Confidence);
}
catch
{
Console.WriteLine("Error!");
return -3; // Unhandled error
}
},
errs => Task.FromResult(-1)); // Invalid arguments
}
Здесь вы можете увидеть все изменения по сравнению с предыдущей версией кода.
С этими изменениями приложение корректно анализирует наши аргументы. Для нас даже есть страница помощи, созданная автоматически!
Допустим, вы хотите проанализировать изображение, но хотите получить результат, даже если вы не слишком уверены в нем, скажем, с доверием 30%. Теперь это легко сделать с помощью аргумента -c (--confidence). С этим изображением:
Вы можете получить этот результат, используя --confidence:
> .ImageClassifier.exe C:\Users\alzollin\Downloads\NotALion.jpg --confidence 0.3
Image 'C:\Users\alzollin\Downloads\NotALion.jpg' is classified as 'Persian cat'(p=58%).
Заключение
Пакет NuGet CommandLineParser - очень мощный помощник, который упрощает эту часто повторяющуюся задачу до простого декларативного подхода. Кроме того, он даже еще более кастомизируемый, чем я продемонстрировал здесь. Вы можете найти его документацию на их странице GitHub вики.