参考自http://www.ndesk.org/doc/ndesk-options/NDesk.Options/index.html

写在前面

国内貌似还没有关于NDesk.Options的中文介绍,因此在官方教程基础上,对NDesk.Options进行简单总结介绍。

个人水平有限,不能很好的表达原作者意图,请各位见谅!

总体介绍

NDesk.Options是用于C#命令行参数解析的开源库,又名Mono.Options。支持解析布尔参数(Boolean Options)、值参数(Value Options)、捆绑参数(Bundled parameters)。在进行参数解析的时候,允许自定义回调函数。

官方网页地址为http://www.ndesk.org/Options

Github上地址为https://github.com/mono/mono/tree/master/mcs/class/Mono.Options/

代码示例

准备通过官方例子,讲解NDesk.Options的用法。如果有时间和精力再继续完善补充更多例子。

全篇文章将根据该示例进行讲解,请先大体了解下代码结构,后面会对NDesk.Options用法进行介绍。

using NDesk.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NDeskOptionDemo
{
    class Program
    {
        static int verbosity;

        public static void Main(string[] args)
        {
            bool show_help = false;
            List<string> names = new List<string>();
            int repeat = 1;

            // 第一阶段:初始化
            var p = new OptionSet() {
            // 注册 解析必填参数(required)、参数描述、解析回调函数
            { "n|name=", "the {NAME} of someone to greet.",
              v => names.Add (v) },
            // 注册解析必填参数(required)、参数描述、解析回调函数
            { "r|repeat=",
                "the number of {TIMES} to repeat the greeting.\n" +
                    "this must be an integer.",
              (int v) => repeat = v },
            // 注册解析布尔参数(boolean)、参数描述、解析回调函数
            { "v", "increase debug message verbosity",
              v => { if (v != null) ++verbosity; } },
            // 注册解析布尔参数(boolean)、参数描述、解析回调函数
            { "h|help",  "show this message and exit",
              v => show_help = v != null },
        };

            List<string> extra;
            try
            {
                // 第二阶段:解析,未解析的参数将放置到变量extra中
                extra = p.Parse(args);
            }
            catch (OptionException e)
            {
                Console.Write("greet: ");
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `greet --help' for more information.");
                return;
            }

            if (show_help)
            {
                ShowHelp(p);
                return;
            }

            string message;
            if (extra.Count > 0)
            {
                message = string.Join(" ", extra.ToArray());
                Debug("Using new message: {0}", message);
            }
            else
            {
                message = "Hello {0}!";
                Debug("Using default message: {0}", message);
            }

            foreach (string name in names)
            {
                for (int i = 0; i < repeat; ++i)
                {
                    //Console.WriteLine("-------------in loop--------------");
                    //Console.WriteLine("message = {0}", message);
                    //Console.WriteLine("name[{0}] = {1}", i, name);
                    Console.WriteLine(message, name);
                    
                } 
            }

            Console.ReadKey();
        }

        static void ShowHelp(OptionSet p)
        {
            Console.WriteLine("Usage: greet [OPTIONS]+ message");
            Console.WriteLine("Greet a list of individuals with an optional message.");
            Console.WriteLine("If no message is specified, a generic greeting is used.");
            Console.WriteLine();
            Console.WriteLine("Options:");
            p.WriteOptionDescriptions(Console.Out);
        }

        static void Debug(string format, params object[] args)
        {
            if (verbosity > 0)
            {
                Console.Write("# ");
                Console.WriteLine(format, args);
            }
        }
    }
}

使用介绍

参数解析分为两个阶段:初始化和解析。分别对应上面代码var p = new OptionSet() {...} 和p.Parse(args);

NDesk.Options会把“-”、“--”、“/”认为是参数名(OptionName)进行解析并赋予参数值(OptionValue),举例说明

a.exe -n 10 --name=9  /opt:true ?123

经解析后,参数名n的参数值为10,name的值为9,opt的值为true。而?123是未被处理的多余字符串。在未定义默认解析函数情况下,经解析后多余字符串会通过parse()函数返回,例如下面的extra就存放了多余字符串:

public static void Main(string[] args)
{
    ...

    List<string> extra = p.Parse(args);

    ...
}

关于默认解析函数请参考下一节内容

初始化

初始化的目的对于使用者来说就是注册要解析的参数名、参数名的描述以及匹配到参数名后的回调函数。例如

var p = new OptionSet() {{ "n|name=", "the {NAME} of someone to greet.",  v => names.Add (v) }}
  • "n|name=" 表示参数名原型(Prototype),此处表示该参数名可以缩写为-n或者全称-name(注意先要声明参数名缩写,再声明参数名全称
  • "the {NAME} of someone to greet."作用时在调用p.WriteOptionDescriptions(Console.Out)后,将打印出该参数名的描述
  • v => names.Add (v)表示在解析到参数名n时将参数值添加到names中(lamda表达式)

如果想为这些未匹配的参数名提供默认解析函数,可以这样注册,注意“<>”这个参数名即为默认解析函数

var p = new OptionSet() {
{ "n|name=", "the {NAME} of someone to greet.",  v => names.Add (v) },
{ "<>", v => Console.WriteLine ("default handler: {0}", v)}
}

参数名有三种类型:布尔型(Boolean)、必输型(Required)、选输型(Optional),用无符号、等号、冒号来区别

var p = new OptionSet() {
//布尔,例如采用-opt+、--opt-、/opt均可以为赋值
{ "o|opt", "the {opt} of someone to greet.",  v => flag = (v == null) },
//必输
{ "n2|name2=", "the {NAME2} of someone to greet.",  v => names.Add (v) },
//选输
{ "n3|name3", "the {NAME3} of someone to greet.",  v => names.Add (v) },
}

解析

通例子来说明参数解析,以加深对NDesk.Options的理解。仍然考虑代码示例章节的代码

##show_help为真,执行ShowHelp(p);打印参数名描述
greet.exe --help
Usage: greet [OPTIONS]+ message
Greet a list of individuals with an optional message.
If no message is specified, a generic greeting is used.

Options:
  -n, --name=NAME            the NAME of someone to greet.
  -r, --repeat=TIMES         the number of TIMES to repeat the greeting.
                               this must be an integer.
  -v                         increase debug message verbosity
  -h, --help                 show this message and exit

##v为false,不打印调试信息
##names包含A、B、C、D、E参数值
##extra为空,表示无未处理的字符串,则按照hello XXX!进行打印
##repeat未解析到,采用默认值1,即重复打印1次
greet.exe -v- -n A -name=B --name=C /name D -nE
Hello A!
Hello B!
Hello C!
Hello D!
Hello E!

##v为true,打印调试信息
##names包含E参数值
##extra为 custom greeting for: {0},则按照custom greeting for: XXX进行打印
greet.exe -v -n E custom greeting for: {0}
# Using new message: custom greeting for: {0}
custom greeting for: E

##names包含A参数值
##extra为空,表示无未处理的字符串,则按照hello XXX!进行打印
##repeat为3,重复打印3次
greet.exe -r 3 -n A
Hello A!
Hello A!
Hello A!

##repeat只能接受int类型,不能将not-an-int转换成int,抛出异常
##源代码中关于reapeat类型检查,代码为(int v) => repeat = v
greet.exe -r not-an-int
greet: Could not convert string `not-an-int' to type Int32 for option `-r'.
Try `greet --help' for more information.

 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐