返回首页

{A}{A2的}{A3的}{S0的}介绍
任何非平凡的程序通常会为用户提供了一些选项。对于一个控制台应用程序,这些都是传统的C#应用​​程序作为一个字符串数组,例如主要方法是通过命令行参数指定:

static void Main(string[] args) { }

这些参数需要解析。这可以通过手工编码自定义实现,但它很容易出错,变得乏味实施后,这几个应用程序。这个问题已经面临很多程序员,并导致各种库,例如getopt的C和UNIX与Java和C#的类似端口。 getopt的和其他的方法的问题是,它仅自动化进程的一部分。他们仍然需要开发人员有时通常包含一个大的switch语句实现一个处理循环,并产生错误的事件和其他各种安装程序在使用字符串。
这篇文章显示了不同的方式为C#使用{A4}库。这消除了需要开发实施任何解​​析代码。它也改变了命令行参数处理必须从一个声明的编程模型。这意味着,所有的开发人员需要做的是指定成员变量,成员属性和/或成员函数应在回应在场的命令行参数设置。
从必要的声明风格的转变是由LINQ查询的地方搬到实施(必要)刚刚宣布什么查询应该做的(声明)介绍说,类似。而LINQ的使用额外的C#编译器的语法糖,使开发过程非常容易,NAttrArgs库顾名思义依赖。NET属性。
为NAttrArgs库的源代码,库的二进制文件的例子,加上提供作为随行拉链。源代码是开源的,是GitHub上为{A5的}。使用代码
看到如何NAttrArgs工作的最简单的方法是用一个简单的例子开始。{C}
这显示了一个简单的程序,有一个必需的参数和一个可选的标志参数。而不必添加任何特殊的解析代码,最终的结果应该是,如果这些命令行参数,然后装饰与NArg属性的变量应设置适当。
不带任何参数运行产生下列输出:
Usage: Example2 [-foo] <_testArg>

这是因为该计划预计将提供价值为_testArg。这是宣布使用空NArgAttribute。默认情况下,一种说法是强制性,除非属性参数IsOptional的设置为true。这被认为是在声明的第二个变量_optionalFlag。
有两种类型的可选参数,首先一个布尔标志的参数,它代表一个设置,可以开启或关闭,如"somecmd递归"。其次,有一个可选的参数,需要一个参数,如的"somecmd-bgcolour红'。在这些情况下,如果没有指定该选项,那么该变量的值将保持不变。在上面的例子中,如果指定'富',然后_optionalFlag将设置为true。
作为指定任何命令行参数,调用parse()的抛出一个异常,因为它预计至少找到一个参数,可以用来设置值_testArg。用法消息构造由NAttrArgs与存储在的抛出NArgException的Message属性。
用法消息的格式是构造可选参数到的ArgParser的指定程序的名称;如果有的话,那么,如果有任何强制性的参数和最后一个椭圆表示一个变量(字符串类型[])已被指定接收任何未使用的参数,有没有在这个例子中。
在使用消息的每个参数的名称是默认情况下,相关的变量的名称。可以看出,名称_testArg是不是很友好。通过使用的AltName选项的NArg属性的参数可以与一个不同的名称。这是用来显示quot; fooquot情况_optionalFlag。
相反,如果示例程序运行的命令行参数'富'和'bar',它显示:{体C3}
发生了什么是'酒吧'的价值,已_testArg变量设置。由于变量是字符串类型,然后从一个命令行参数字符串给一个字符串变量的映射很简单。中的_optionalFlag的情况下,有没有实际的命令行参数值来设置。相反选项的存在导致的NAttrArg的解析代码,这个变量的值设置为true。
接收变量的类型不仅限于字符串和bool明显的例子。他们可以设置什么。NET Convert.ChangeType方法的可处理。此外,允许转换为bool从char;但是,这只是在内部使用时的一个可选的标志变量的类型是char和内部代码尝试将其设置为true。此外,以及类型转换,如果是从通过Type.IsAssignable的源类型指定的目标类型(变量),那么这是用来。这也主要是用于处理内部使用时的特殊情况下,剩下的参数作为一个字符串存储,而不是被分配到了这种类型的变量,他们,而不是分配给类型IEnumerablelt财产; stringgt;
如果转换是不可能的,例如:变量的类型是双和命令行参数(这将始终是一个字符串),是'酒吧'的价值,而不是说'2 0.37",那么这将导致Convert.ChangeType引发异常。这将陷入内的ArgParse.Parse方法将抛出一个NArgAttrException。像以前一样,使用信息将包含在Message属性,但除了原有的例外是从InnerException属性。
这似乎是不雅和不完整的方式来处理这种情况。相反,它消除了处理这从开发商的负担。由指定的接收值的变量的类型,有一个隐含的命令行参数字符串值必须转换合同。如果不是的话,那么这是一个用法错误。用法消息不指定可接受的值是什么。对于任何数量,这将难以给予无限的范围内。它可能会指定一个可接受的格式。然而,设计和惯例用法消息通常不转达这一信息。相反,它留给应用程序的文档。
NAttrArgs"不过有一个选项,捕捉转换之前不正确的值,并显示在使用信息的可接受值。这是通过使用AllowedValues​​参数的NArg属性。这需要一个可接受的值的字符串数组。这些值之前检查到任何类型的转换。下面的例子是前一个修改后的版本。{的C4}
强制性参数,现在只接受要么'一','两个'或'三'。稍微有趣的例子是,现在限制为'true'或'false'布尔变量_optionalFlag的,这是有道理的,因为它的布尔。然而,指定的AllowedValues​​的参数改变了这一选项需要一个参数从一个可选的标志。用法消息显示:{C5的}
后者的修改是指定'-foo的真正的'是因为以前只是用'富'一样毫无意义。因此,限制值的好处取决于目标变量的类型。用法消息也改变了当值的约束。 ,而不是使用的变量的名称或替代名称,允许值的清单显示,由管道符号隔开('|'),意思是'或'作为来自UNIX正则表达式。
的例子迄今只涉及单一的可选性和强制性的参数。有一个可选参数的隐式顺序,其次是强制性参数。如果有不止一个,每个参数的类型和顺序是重要的,然后排名参数的NArg属性的应用。这是所示,其中有三个强制性和三个可选参数。
如果没有指定排名,但存在多个强制性或多个可选参数,然后解析顺序将对应的装饰(与NArg属性)成员的定义顺序。默认情况下,排名的价值是0,使所有的论点都是平等的,所以定义的顺序为准。
相应的用法消息是:{C7-}
的定义顺序已被取代的等级参数。请注意没有排名如何给_optionalArg1这意味着它保留了0级,这是最高的。要改变这个变量的位置,无论是较低级的需要,指定或其他装饰变量之前需要定义。它不只是这可装饰的变量
到目前为止,只有成员变量已装饰用的属性。它不是唯一明确的成员变量,可以有自己的价值集。只要有一个setter方法​​,可以指定一个属性。对于这项工作,它必须有没有参数或一个参数,这是一个命令行参数可以转换的类型。有没有参数可能看起来有点古怪,但一个可选的标志参数,它是一个完美的映射,调用意味着论据是目前。尽管它没有太多的点,有没有一个可选的或强制性的参数,防止使用无效的方法。
调用setter方法​​,在特定的方法,使能力之间的命令行参数和最终设置更复杂的映射。下面的例子演示了如何设置一个变量在命令行中获得的值,并乘以一个可选的命令行值。{C8的}
这个例子也显示了NArg的属性OptionalArgName参数的使用。多重属性不是一个布尔值,需要设置一个uint,可选的参数,因此需要一个参数。此参数的名称(将用于建设使用的消息时)指定由OptionalArgName参数。在可选的名字意味着它是一个可选的参数,不在于它本身是可选的参数。
同样的方法可以被用于不同的命令行参数。然而,如果用一个可选的参数参数,有没有防止重复调用。如果使用不同的值(命令行),可以建立累计值,如"somecmd加1加2加3",累积持有'6'变量的每个值。
能够通过该属性指定的方法,避免了创建一个临时的成员变量来存储收购的价值,用它做的东西之前,在方法。可以想象,将有可能在这些方法之一将整个程序逻辑或从那里开始操作。如果该方法是一个函数(而不是void返回值),这将被忽略。任何剩余的命令行参数会发生什么?
默认情况下,任何无法识别的可选参数,将产生一个错误,并会做任何遗留的非可选参数相同,但对InnerException会有所不同。这种状况是正常的,除非应用程序需要一个无限的最终参数列表的过程中,如一组文件中列出的信息,或倾倒其内容。这是最后NArg IsConsumeRemaining属性的参数使用。
class Program

{

    [NArg(IsOptional = true, AltName = "Count")] 

    public bool IsShowCount { get; private set; }

    [NArg(IsConsumeRemaining = true)] private string[] _theRest;



    private static void Main(string[] args)

    {

        try

        {

            new Program().Run(args);

        }

        catch (NArgException e)

        {

            Console.Error.WriteLine(e.Message);

        }

    }



    private void Run(string[] args)

    {

        new ArgParser<Program>("Example6").Parse(this, args);



        if (IsShowCount == true)

            Console.WriteLine("There are {0} remaining arguments", _theRest.Length);



        foreach (string s in _theRest)

            Console.WriteLine(s);

    }

}

任何剩余的参数,现在变成一个字符串数组,每归咎于任何其他成员可以通过一个变量,属性或方​​法。目标类型必须是从一个String []兑换。特别是如果字符串都是整数和目标类型是int [],然后从字符串到int的转换,即使在这种情况下是合法的,数组类型之间的转换,是不是,即对每个元素进行转换基础。其余字符串值IEnumerablelt; stringgt的分配提供明确的支持;提供演示此替代实施例6。
如果有多个成员都装饰NArg(IsConsumeRemaining = TRUE),那么第一次使用,其余的将不变。饰有这种说法的成员基本上是一个可选的参数,如果没有剩余的参数,那么它会不会引起错误。排名是根据定义,只有命令行值后,所有其他消耗无关。如果任何这些参数的设置,那么它们将被忽略。如过是AllowedValues​​。剩余价值是通过逐字装饰接收他们的成员。用法消息,其余的参数都表示为"[...]"成员的名字也是无关紧要的。NArgAttribute用法
下面是不同性质的总结的NArg属性。并非所有的可以一起使用,但如果发生这种情况会有任何错误。解析机制,而不是将演绎出最适合的使用。如果物业内重复使用的属性,然后在最后一次使用优先。IsOptional句法{C10的}
默认值是假的含义任何装饰与NArg属性的成员被认为是强制性的。排名句法{C11的}备注
默认值是0。被解析时,可选参数之前被认为是强制性的参数。这意味着,可选的和强制性的论点形成两套每个与他们自己的订货参数,所以相同的序号可以使用强制性和可选参数没有冲突。在解析过程中首先考虑的可选参数。
可选参数解析结束时的第一个命令行参数不带前缀" - "遇到。如果额外的命令行参数与开始' - ',那么他们不及时治疗等。AltName句法{C12的}备注
默认情况下,产生的用法消息中使用的名称是装饰的成员的名字。此属性允许显示名称更改为指定的字符串。OptionalArgName句法
NArg(OptionalArgName = <string>) 

此属性仅适用于可选的参数,即,其中IsOptional =真。设置此值,改变了可选的类型从一个可选的标志,一个可选的参数。现在需要在命令行指定的选项和一个额外的参数,如富数8。参数值将被用于设置装饰的成员,而不是真或假的。AllowedValues句法
NArg(AllowedValues = <string[]>) 
备注
此属性允许的值设置为装饰的成员是有限的。这些被指定为字符串,而不是成员的目标类型;如果不同。
用法消息也受到影响,而不是显示一个强制性参数的名称或一个可选的参数的名称,由一个分开的允许值的列表显示"|"符号。
如果此属性设置除了IsOptional =没有OptionalArgName指定,然后允许值不再布尔可选的标志参数是隐式晋升成为一个参数指定的值可选参数。这是真实的,即使允许值只是'真'和'假'。IsConsumeRemaining句法
NArg(IsConsumeRemaining = true | false) 
备注
默认情况下,如有剩余的命令行参数是杰出的,一旦所有的可选性和强制性的参数匹配,那么这个被认为是一个错误。
设置此属性的对装饰与NArg属性成员将不再意味着,出色的命令行参数构成一个错误。相反,他们将被分配到装饰的成员。这必须是字符串类型[]或IEnumerablelt; stringgt;如果没有优秀的参数,然后将被分配一个零长度字符串数组,即目标成员将不能为空。没有其他的类型转换发生。
与NArg属性,有此属性集装饰,只有一个单一的成员,这是有道理的。如果有一个以上的发生,那么首先使用。没有其他NArg的属性的属性是适用于与此属性。如果指定的话,他们将被忽略。这包括AllowedValues​​。你不仅限于控制台应用程序
虽然的NAttrArgs库的主要应用是控制台应用程序的命令行参数的处理,这是不是唯一的使用。 GUI应用程序的命令行参数,虽然不常使用此功能,这是很正常的。在下面的代码示例7显示NAttrArgs被用来处理命令行参数传递到一个WPF应用程序和修饰的成员变量在XAML中使用的摘录。
注:获得通过{A6的}命令行参数时,第一个参数包含可执行文件的路径,而参数传递到一个C#控制台应用程序不。app.xaml.cs{C16的}MainWindow.xaml 测试驱动开发(TDD)
这个库是我第一次尝试使用{A7的}。
代码已发展到非常颗粒很多,很容易在隔离测试的小班。代码没有启动这种方式。最初它是一个单独的类,然后大量较小的类,然后再返回到一个或两个大类别,在其目前的状态终于结束了。正因为如此,相当多的一些测试,特别是那些测试参数解析和使用消息在过于更高的层面,并应考虑要么整合或验收试验。现在让这些被视为一个单元测试,每级的基础上,一套正确实施当前的解析代码的细粒度实施合理的罚款。
表演拓展署一直是一个有趣的经验。起初它就像编程里面,但更习惯了,我成了,这是容易。允许拥有一套单元测试(测试和验收测试)不断重构代码,如前所述。重构发生深远的内部类的类和方法提取出的条件。只要能够经常运行测试,有152和他们在一两秒钟的运行;意味着,检查重构曾是微不足道的。
除了使用TDD,写一个测试程序使用NAttrArgs。这是一个简化版本的{A8的}使用的UNIX。这是一个孤立的框架,它具有可用于密封类,静态类和静态和非虚方法的类的创建,测试双打的有用的属性。在。NET文件系统中的类的情况下,即文件,FileSystemInfo,的FileInfo和DirectoryInfo这是肯定的情况下。
若要启用此,痣使用少走弯路,这似乎是拦截方法调用和重写这些方法的使用。NET分析API动态。这个额外的功能的缺点是,单元测试采取数量级更长的时间比基于NUnit的测试运行。为了与Visual Studio集成,为LS样品的测试,而不是使用MSTest的书面NUnit的。这是必要的,如痣,在使用时要使用(设置分析API){A9的}痣相关的测试运行,这是需要。只要能够在Visual Studio中推出MS测试是为每个测试装饰鼹鼠的自定义属性:[HOSTTYPE("Molesquot ;)。
拓展署红 - 绿 - 重构过程的一部分,这已采取进一步比平时是重构阶段。最近看了Bob大叔的{A10的}常降低。然而,这是经常发生的情况,很有凝聚力,这意味着一个独立的类可以提取方法的子集。这是可取的,并导致高度凝聚力的,但松散耦合的代码。 包是什么?
的NAttrArgs解决方案有三个主要领域。首先,是的NAttrArgs项目本身。这是为NAttrArgs库时建在NAttrArgs.dll装配源。其次,是NAttrArgs.Test的项目,该项目是基于为NAttrArgs NUnit的测试。最后,还有一个解决方案的样品目录,其中包含在ls项目例如ls命令和陪MS测试/痣的单元测试在ls.TestMS项目。这并不表明,许多的NAttrArgs功能,还有被称为测试的最后一个项目。这个项目是一个简单的程序,演示每个NAttrArgs能力。
注:不同的是NUnit的二进制文件,二进制文件的痣没有提供。这是由于微软的许可证只允许用于非商业和学术的用户免费使用。如果从ls.TestMS项目的测试需要运行,那么请从Microsoft获得适当的副本。这个解决方案是不包的一个重要组成部分,只留在为别人可能觉得很有意思,看看如何可以测试两双。NET文件系统中的类创建。"守则"
由于使用TDD(包括在场的测试),加上小,但希望以及命名方法的使用,则代码应该是自我描述。这就是说,两个主要的地方看看ArgParser.cs和NArgAttribute.cs。后者则是用来装饰类成员的自定义属性的定义。构造ArgParser启动这些通过使用反射来获取所以装饰类的所有成员使用。三个名单,以及LINQ查询创建代表必需的,可选和剩余装饰的成员,如果有任何。这些查询不返回实例NArgAttribute而派生类MemberAttribute的。这增加了主要的事情是与NArgAttribute装饰类成员参考。
命令行参数的解析工作是交给序列可选的,必需的和强制性的类似命名的文件中包含的解析器。这些一个的ArgIterator类的实例。实现IEnumeratorlt stringgt;列举的访问,并提供命令行参数。自定义实现,而不是仅仅获得的String []的一个实例,原因是额外的行为,使目前的项目要推回。这是使用可选参数分析器,当它遇到的第一个必需的选项,因此需要推回的RequiredArgumentsParser消费的论点。
利益的其他主要类别的MemberSetter和CustomConvert。当解析器发现了他们目前的说法MemberSetter匹配的成员是用来设置值。根据该成员的类型,这将既可以设置一个变量或属性值或调用一个方法。由在MemberAttribute相结合的NArgAttribute和MemberInfo的信息可以传递到MemberSetter处理成员的统称,无论它是否是一个可选的还是必需的参数。这个类项为可选的,必需的和剩余的参数点,但这些都是由一个共同实施从MemberAttribute使用的MemberInfo要弄清楚如何访问成员变量,属性或方​​法处理。
设置值时,CustomConvert类处理任何必要的命令行参数字符串类型和目标类型之间的转换。这主要是使用。NET方法Convert.ChangeType的,但这个类处理从一个bool转换为一个目标类型是一个可选的标志时,只需要一个char字符的特殊情况。另一方面,没有特殊情况是当目标类型是从源类型指定。这增加了这样的字符串[]创建,处理剩余的参数,可以应用到目标类型的IEnumerablelt; stringgt;因为这是不能自由兑换。然而,这是其他类型的直接分配,转换可避免。下一步是什么?
这是NAttrArgs V1的。一些额外的功能立即映入脑海的是:
扩展用法消息
除了显示生成的用法消息,这将允许下将显示用法消息提供的参数的可选更长的描述。
允许单一字母可选的标志被合并成一个字符串
例如:而不是-ABC-A-B-C
允许指定的可选参数值没有空间紧随选项或使用等号(=)
例如: foob​​ar的,而富比的酒吧或富=酒吧重因子的单元测试,完全是每级创建一个{A11}的二进制包
如果任何上诉,或是否有别的东西,会使用,请让我知道。另外,叉{A12}和贡献的任何变化,如果你喜欢。

回答

评论会员:游客 时间:2012/02/07
Ado_Civon:嗨,我只是在玩弄与社会分享你的论点分析器和感谢。我有一个小问题,可能是用户的错误,但事情似乎并不要为我工作:使用如下:{C18的}{C19的}以下参数测试应用程序通过调用中,_function字符串不被填充。TestApp.exe-F等等我得到的反应:用法:[-F]如果我设置"AllowedValues​​",它工作正常。更新1:在另一方面,如果下面的调用:TestApp.exe-F其结果是:_TestArgs:真更新2:如果设置"OptionalArgName",它工作正常。{C20的}输入:TestApp.exe-FsomeText输出:_TestArgs:someText修改为'121月17日:PeteBarber
|,

感谢您的详细信息。我读过通过它,你怎么描述它的工作是如预期。我认为,混乱是在文章中被称为"可选的标志参数"(布尔标志参数)和"可选的参数,需要一个参数"之间的区别。

例如:

[NArg(IsOptional =真实,AltName ="F")]
公共字符串_function的;

声明一个可选的标志参数,它可以开/关。在命令行上提供"-F"将导致被设置为_function _function是真实的,以及不正确的,因为这样反而会被设置的Convert.ChangeType(真实的,typeof运算(字符串))的结果,这是一个字符串,字符串"true"。

我想你想-F接受一个参数,在这种情况下,它需要有一个可选的参数,这就要求在最后的例子中所使用的规范参数,即更新2:
[NArg(OptionalArgName ="T",AltName ="F",IsOptional = TRUE)
私人字符串_function的;

这里OptionalArgName修改参数的可选参数。仅用于发电的帮助时,指定的名称。它仍然是装饰的成员设置,在这种情况_function,。

正如你看到的AllowedValues​​设置使用一个可选的标志参数变成一个"可选的参数,它需要一个参数",但在这种情况下,有限的允许值
评论会员:wvd_vegt 时间:2012/02/07
思想伟大!

但要真正有用,它可以使用一些更多的代码(所以没有投票),如:1)说明什么开关选项的意思是,2)倾销一行上所有的语法是坏为readabilty /了解,3)作为类型的文件名。
评论会员:PeteBarber 时间:2012/02/07
1。我同意选项的说明将是有益的。这是所提到的可能增加。

2。这是标准的方式与命令行选项,尤其是UNIX工具。

3。请你澄清"作为类型的文件名"的功能。听起来很有趣,有益的。

感谢
评论会员:游客 时间:2012/02/07
wvd_vegt:嗨它是在UNIX的标准方式,并不意味着它是最优的,只有它的老办法仍然沿袭习惯imgsrc=http://www.orcode.com/img/ico/smiley_wink.gif。我个人更喜欢更多的格式和详细的输出,经验不足的用户可以了解和描述默认情况下显示。至于文件名,我MENT,你可能标志着一个字符串财产思想是一个文件名,应该或不应该extist,在一个有效的位置(所以你的代码可以做检查,和完全消耗的文件名)。它也可能是一个单独aliasses和命令的缩写的想法一个单独的attibute(然后,你可以让多个aliasses)wvd_vegt
约翰・布雷特
评论会员:游客 时间:2012/02/07
的尼斯文章。我太喜欢尝试拓展署的经验说明,顺便说一句-我用自己的工具命令行解析了类似的策略。我用,我没有发现在你最的特点之一是解析枚举。如果你真的想"把一个GUI前端",在您的控制台应用程序,我在过去所采取的方法是只在你的代码配置到一个类里面/结构独立于主程序。然后,您可以使命令行配置(如使用您的NAttrArgs)或填补它通过形式
|喜约翰,PeteBarber:

感谢您的反馈。解析枚举前面,你会想看到做呢?我在想,一个枚举可以使用的价值,而不是字符串[] AllowedValues​​。另外,如果枚举类型的成员,也将作为AllowedValues​​。

你心里有没有别的东西吗?

谢谢,

皮特
:约翰・布雷特:我添加枚举我相当于你CustomConverter类的支持。虽然您的代码可以很明显限制了一套有效的字符串,我想更强烈输入的解决方案,其中包括使用显示有效的枚举值列表。这只是一些我没有看到你的代码(如果我忽略了它的道歉)。
出于某种原因,我刚刚发现自己的命令行实用工具枚举非常有用的
评论会员:萨沙・巴伯 时间:2012/02/07
我已使用年龄这一条,
{A13号}
,我喜欢它,所以你的想法肯定是一个从我5(虽然我认为我会坚持我知道)。

还有5从我这里的伟大的工作
萨沙理发
微软的Visual C#MVP 2008 2012Codeproject MVP 2008-2011Open源码
{A14高速公路}

你最好的朋友就是你。
我是我最好的朋友。我们有着相同的看法,并未落认为

我的博客:{A15}
评论会员:PeteBarber 时间:2012/02/07
感谢您的意见。我喜欢这个主意。我写了这些年来工作,但我想一个版本,我会用我自己的东西,加上它看起来像一个有趣的项目申请拓展署
评论会员:游客 时间:2012/02/07
萨沙・巴伯:公平竞争,你做了什么酷萨沙理发微软的VisualC#MVP20082012CodeprojectMVP2008-2011Open源码{A14高速公路}你最好的朋友就是你。我是我最好的朋友。我们有着相同的看法,并未落认为我的博客:{A15}