zoukankan      html  css  js  c++  java
  • C#/.NET 使用 CommandLineParser 来标准化地解析命令行

    CommandLineParser 是一款用于解析命令行参数的 NuGet 包。你只需要关注你的业务,而命令行解析只需要极少量的配置代码。

    本文将介绍如何使用 CommandLineParser 高效写出自己程序的命令行解析部分。


    NuGet 包和 GitHub 开源仓库

    最简单的命令行解析

    using System;
    using System.Collections.Generic;
    using CommandLine;
    
    namespace Walterlv.Demo
    {
        class Program
        {
            public class Options
            {
                [Option('f', "file", Required = true, HelpText = "需要处理的文件。")]
                public IEnumerable<string> Files { get; set; }
    
                [Option('o', "override", Required = false, HelpText = "是否覆盖原有文件。")]
                public bool Override { get; set; }
            }
    
            static void Main(string[] args)
            {
                Parser.Default.ParseArguments<Options>(args).WithParsed(Run);
            }
    
            private static void Run(Options option)
            {
                // 使用解析后的命令行参数进行操作。
                foreach (var file in option.Files)
                {
                    var verb = option.Override ? "覆盖" : "使用";
                    Console.WriteLine($"walterlv 正在{verb}文件 {file}");
                }
            }
        }
    }
    

    这个简单的 Demo 程序使用 Options 类来封装命令行参数,Parser.Default.ParseArguments 解析到的参数将存入 Options 类型的实例中。而只需要加上 WithParsed 即可在一个新的方法中使用我们解析后的 Options 实例。

    这时,在命令行中就可以使用命令了:

    dotnet demo.dll -f C:UserslvyiDesktopTest.txt
    

    在命令行中使用命令

    由于我们标记 Files 是必要属性,所以如果此参数没有指定,将返回命令行的使用说明。此使用说明中就包含了我们在 Option 参数中编写的 HelpText

    如果你的 Options 类中单次是多单词的短语,那么建议在指定名称的时候为每一个单词之间添加一个空格。这样参数就不会让多个单词连成一片难以辨认。

    例如:

    public class Options
    {
        [Option("long-name", Required = true, HelpText = "需要处理的文件。")]
        public string LongName { get; set; }
    }
    

    那么命令是:

    dotnet demo.dll --long-name xxx
    

    如果不指定,那么就是 --longname,这显然不好看。

    包含多个方法的命令行解析

    如果一个命令行程序只做一件事情,那么以上代码足以应付大多数的情况。可是有时候一个命令行程序是为了做一类事情的 —— 典型的例子就是 git 程序。当你运行 git 的时候,你可以在 git 后面加一个谓词(动词),表示执行的是哪一个命令。后面的参数是每个命令都不同的,并且第一个参数是不用指定名称的。

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using CommandLine;
    
    namespace Walterlv.Demo
    {
        [Verb("check", HelpText = "检查")]
        class CheckOptions
        {
            [Value(0, HelpText = "一个 .sln 文件,一个或者多个 .csproj 文件。")]
            public IEnumerable<string> InputFiles { get; set; }
        }
    
        [Verb("fix", HelpText = "修复")]
        class FixOptions
        {
            [Value(0, HelpText = "一个 .sln 文件,一个或者多个 .csproj 文件。")]
            public IEnumerable<string> InputFiles { get; set; }
    
            [Option('o', "outputFiles", Required = true, HelpText = "修复之后的文件集合。")]
            public IEnumerable<string> OutputFiles { get; set; }
    
            [Option(Required = false, HelpText = "是否自动决定版本号,这将使用冲突版本号中的最新版本。")]
            public bool AutoVersion { get; set; }
        }
    
        class Program
        {
            static int Main(string[] args)
            {
                var exitCode = Parser.Default.ParseArguments<CheckOptions, FixOptions>(args)
                    .MapResult(
                        (CheckOptions o) => CheckSolutionOrProjectFiles(o),
                        (FixOptions o) => FixSolutionOrProjectFiles(o),
                        error => 1);
                return exitCode;
            }
    
            private static int CheckSolutionOrProjectFiles(CheckOptions options)
            {
                return 0;
            }
    
            private static int FixSolutionOrProjectFiles(FixOptions options)
            {
                return 0;
            }
        }
    }
    

    对于这一段程序,我们可以使用两种不同的谓词来执行命令:

    dotnet demo.dll check C:UserslvyiDesktopTestTest.csproj
    
    dotnet demo.dll fix C:UserslvyiDesktopTestTest.csproj -o C:UserslvyiDesktopTestFixTest.csproj
    

    Verb,Option 和 Value

    Verb 是在一个命令行选项的 Option 类上标记的,用于指定命令的类别。每一个 Verb 标记的类别都可以有自己独立的一套命令行参数。

    Option 是命名的命令行参数。在命令行中,你必须指定命令行缩写或者全称来指定命令行参数的不同类型。

    Value 是命令行的无名参数,它是靠在命令行谓词后面的参数位置来确定解析到哪一个属性上的。


    参考资料


    我的博客会首发于 https://walterlv.com/,而 CSDN 和博客园仅从其中摘选发布,而且一旦发布了就不再更新。

    知识共享许可协议

    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://blog.csdn.net/wpwalter),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

  • 相关阅读:
    Apache Spark 2.2.0 中文文档
    Apache Spark 2.2.0 中文文档
    Apache Spark 2.2.0 中文文档
    Apache Spark 2.2.0 中文文档
    Apache Spark 2.2.0 中文文档
    Apache Spark RDD(Resilient Distributed Datasets)论文
    Apache Spark 2.2.0 中文文档
    Apache Spark 2.2.0 中文文档
    【机器学习实战】第10章 K-Means(K-均值)聚类算法
    [译]flexbox全揭秘
  • 原文地址:https://www.cnblogs.com/walterlv/p/10236378.html
Copyright © 2011-2022 走看看