Cinchoo - 简化的命令行参数解析器
易于使用的命令行参数解析器,具有用法创建、类型安全管理等加载功能
目录
- 目录
1. 引言
Cinchoo 是 .NET 应用程序框架。它提供给用户的主要功能之一是应用程序配置管理。应用程序配置是应用程序在运行时从源读取和/或写入的信息。
大多数程序以某种形式接受命令行参数。对命令行参数进行编程解析和使用是重复而枯燥的任务。将其作为一个库,让您可以专注于核心开发任务。有许多解析器可用,它们可以为您完成这项工作。Cinchoo 就是其中之一,但它在您的项目中非常易于使用。亲自尝试并感受一下。
Cinchoo 提供了一个简洁易用的 API 来使用命令行参数。它允许您
- 显示用法文本
- 报告语法错误的方式
- 类型安全对象管理
- 支持值转换器
- 支持自定义验证
- 从文件读取命令行参数等。
2. 要求
这个命令行库是用 C# 为 .NET 4.0 Framework 编写的。它是 Cinchoo 框架的一部分,这是一个很棒的库,具有许多功能,如配置管理、通用 ApplicationHost、Shell 功能等。
3. “Hello World!” 示例
我们先来看一个简单的例子,一个应用程序接受两个命令行参数:name (-name) 和 message (-msg)。name 是必需参数,而 msg 是可选参数,默认值为 "Good Morning"。如果 msg 未传递,它将采用默认值。
- 下载最新的 Cinchoo 二进制文件此处。(Nuget 命令:Install-Package Cinchoo)
- 打开 VS.NET 2010 或更高版本
- 创建一个示例 VS.NET (.NET Framework 4) 控制台应用程序项目
- 添加对 Cinchoo.Core.dll 的引用
- 使用
Cinchoo.Core.Shell
命名空间 - 复制并粘贴下面的命令行对象
清单 3.1 定义命令行对象
[ChoCommandLineArgObject(ApplicationName = "Hello world", Copyright = "Copyright 2014 Cinchoo Inc.")]
public class HelloWorldCmdLineParams : ChoCommandLineArgObject
{
[ChoCommandLineArg("name", IsRequired = true, Description = "Name of the person.")]
public string Name
{
get;
set;
}
[ChoCommandLineArg("msg", DefaultValue = "Good Morning", Description = "Greeting message.")]
public string Message
{
get;
set;
}
public override string ToString()
{
return "{0}! {1}.".FormatString(Message, Name);
}
}
上面的代码演示了如何定义命令行参数对象。首先,从 ChoCommandLineArgObject 类定义一个命令行参数(例如 HelloWorldCmdLineParams),它表示此对象是一个命令行参数对象。并且它必须用 ChoCommandLineArgObjectAttribute 修饰才能完成定义。在此示例中,我们指定了应用程序的名称和版权信息。这些值由解析器用于在控制台窗口上显示格式化消息。如果未指定这些选项,则入口程序集的 AssemblyTitle 和 AssemblyCopyright 将分别默认为这些成员。
将命令行参数成员 name 和 msg 定义为公共字段或具有 get 和 set 访问器的属性。使用 ChoCommandLineArg 属性修饰它们,以指示它们是命令行参数。在此示例中,name 属性被赋予 name 作为命令行开关,其 IsRequired 为 true。 这意味着在运行时,此参数必须作为命令行参数传递给此可执行文件,并带有值。Description 用于为此选项提供简短的帮助文本。Message 属性被赋予 msg 开关名称和 DefaultValue。 它是一个可选的命令行参数,如果未传递值,它将默认为 "Good Morning" 文本。
这是使用属性指定命令行选项的非常简单明了的方式。
列表 3.2 Main 方法
class Program
{
static void Main(string[] args)
{
HelloWorldCmdLineParams cmdLineParams = new HelloWorldCmdLineParams();
Console.WriteLine(cmdLineParams.ToString());
}
}
我们首先创建一个新的 HelloWorldCmdLineParams 对象,仅此而已。解析器在后台完成了所有解析和加载命令行参数到对象的繁重工作。如果使用 name 参数值 Raj 运行可执行文件,它将显示 "Good Morning! Raj."
下面列出了程序使用不同参数集及其输出的测试运行。
清单 3.3 Test1.exe 没有参数
>Test1.exe Hello world [Version 1.0.0.0] Copyright 2014 Cinchoo Inc. Missing arg value for 'name' required command line switch. Test1.exe [/msg:<string>] /name:<string> /msg Greeting message. /name Name of the person.
清单 3.4 Test1.exe 带 /?
>Test1.exe /? Hello world [Version 1.0.0.0] Copyright 2014 Cinchoo Inc. Test1.exe [/msg:<string>] /name:<string> /msg Greeting message. /name Name of the person.
清单 3.5 Test1.exe 带 -name 参数
>Test1.exe /name:Raj Hello world [Version 1.0.0.0] Copyright 2014 Cinchoo Inc. Good Morning! Raj.
清单 3.6 Test1.exe 带引号参数
>Test1.exe /name:"Raj Nagalingam" Hello world [Version 1.0.0.0] Copyright 2014 Cinchoo Inc. Good Morning! Raj Nagalingam.
清单 3.7 Test1.exe 带 -name 和 -msg 参数
>Test1.exe /name:"Raj Nagalingam" /msg:"Hello world" Hello world [Version 1.0.0.0] Copyright 2014 Cinchoo Inc. Hello world! Raj Nagalingam.
清单 3.8 Test1.exe 带错误条件
>Test1.exe /name:" " /msg:"Hello world" Hello world [Version 1.0.0.0] Copyright 2014 Cinchoo Inc. Missing arg value for 'name' required command line switch. ConsoleApplication2.exe [/msg:<string>] /name:<string> /msg Greeting message. /name Name of the person.
到目前为止,我们已经看到了一些在可执行文件中使用命令行参数的示例。请尝试其他组合以进行测试。
4. 命令行参数的类型
有两种类型的命令行参数可供选择
- 位置命令行参数
- 开关命名命令行参数
4.1 位置命令行参数
它是一个参数,定义用于从命令行参数中的指定位置接受值。位置从值 1 开始。用 ChoPositionalCommandLineArgAttribute 修饰的命令行对象成员将被称为位置参数。
清单 4.1 带位置参数的命令行参数对象
[ChoCommandLineArgObject(ApplicationName = "Hello world", Copyright = "Copyright 2014 Cinchoo Inc.")]
public class HelloWorldCmdLineParams : ChoCommandLineArgObject
{
[ChoPositionalCommandLineArg(1, "Pos1")]
public string PosArg1;
[ChoPositionalCommandLineArg(2, "Pos2")]
public string PosArg2;
[ChoCommandLineArg("name1", Aliases="n1, m", IsRequired = true, Description = "Name of the person.")]
public string Name;
[ChoCommandLineArg("msg", DefaultValue = "Good Morning", Description = "Greeting message.")]
public string Message
{
get;
set;
}
}
在上面的示例中,PosArg1 和 PosArg2 是位置命令行参数。解析器会查看传递的命令行参数,并为它们加载适当的位置值。
清单 4.2 Test1.exe 带位置参数
>Test1.exe CPos1 /name:"Raj" /msg:"Hello world" CPos2 Hello world [Version 1.0.0.0] Copyright 2014 Cinchoo Inc. -- ConsoleApplication2.HelloWorldCmdLineParams State -- Message: Hello world PosArg1: CPos1 PosArg2: CPos2 Name: Raj
执行程序并使用上述命令行参数后,上述对象成员 PosArg1 和 PosArg2 将分别加载 APos1 和 APos2 值。请注意,位置参数值与开关命名命令行参数混合。当解析和加载位置参数时,解析器会按照从左到右的顺序识别位置参数,从位置 1 开始并加载它们。
4.2 开关命名命令行参数
它是一个参数,定义用于从命令行参数中为指定的命令行开关接受值。用 ChoCommandLineArgAttribute 修饰的命令行对象成员将被称为开关命名命令行参数。
清单 4.3 带开关命名参数的命令行参数对象
[ChoCommandLineArgObject(ApplicationName = "Hello world", Copyright = "Copyright 2014 Cinchoo Inc.")]
public class HelloWorldCmdLineParams : ChoCommandLineArgObject
{
[ChoPositionalCommandLineArg(1, "Pos1")]
public string PosArg1;
[ChoPositionalCommandLineArg(2, "Pos2")]
public string PosArg2;
[ChoCommandLineArg("name", Aliases="n, m", IsRequired = true, Description = "Name of the person.")]
public string Name;
[ChoCommandLineArg("msg", DefaultValue = "Good Morning", Description = "Greeting message.")]
public string Message
{
get;
set;
}
}
在上面的示例中,Name 和 Message 是开关命名的命令行参数。解析器会查找传递的命令行参数中的开关 'name' 和 'msg',并将这些参数与匹配的开关加载到命令行对象中相应的成员中。
清单 4.4 Test1.exe 带位置参数
>Test1.exe CPos1 /name:"Raj" /msg:"Hello world" CPos2 Hello world [Version 1.0.0.0] Copyright 2014 Cinchoo Inc. -- ConsoleApplication2.HelloWorldCmdLineParams State -- Message: Hello world PosArg1: CPos1 PosArg2: CPos2 Name: Raj
执行程序并使用上述命令行参数后,上述对象成员 Name 和 Message 将分别加载 'Raj' 和 'Hello World' 值。
5. 定义命令行参数对象
5.1 属性
5.1.1 ChoCommandLineArgObjectAttribute
此属性应用于将接收并加载命令行参数的类,即定义程序所有可用命令行参数的类。此对象将接收在可执行文件的命令行参数中指定的值。
- ApplicationName - 可选。应用程序名称。如果未指定,则默认为 AssemblyTitle。如果 AssemblyTitle 为空,则默认为入口程序集可执行文件名。
- Copyright - 可选。版权信息。如果未指定,则默认为入口 AssemblyCopyright。
- Description - 可选。描述信息。如果未指定,则默认为入口 AssemblyDescription。
- Version - 可选。版本信息。如果未指定,则默认为入口 AssemblyVersion。
- AdditionalInfo - 可选。可在此处指定其他详细帮助文本。
- DoNotShowUsageDetail - 可选。此标志指示框架是否在用法文本中显示详细信息。默认情况下,它会在用法文本中显示详细信息。默认值为 false。
- ShowUsageIfEmpty - 可选。此标志指示框架在没有向可执行文件传递任何参数时是否显示用法。默认值为 CommandLineParserSettings.ShowUsageIfEmpty 值。
5.1.2 ChoCommandLineArgAdditionalUsageAttribute
此属性应用于命令行参数类,以便为其提供非常详细的描述性帮助文本。您可以多次将其应用于该类。这些文本显示在用法文本的末尾,以换行符分隔。
- AdditionalUsageText - 必填。详细描述性用法文本。
5.1.3 ChoCommandLineArgAttribute
此属性可应用于类的字段和属性,以将其指定为开关命名的命令行参数。此属性指定类的成员接收指定开关的命令行参数值。
5.1.3.1 描述性参数
此属性中有三个描述性参数。
- CommandLineSwitch - 必填。命令行开关。
- ShortName - 可选。开关的短名称,用于生成帮助文本。
- Description - 可选。开关的描述,用于生成帮助文本。
- Aliases - 可选。指定用 ',' 或 ';' 分隔的替代开关
- Order - 可选。指定参数的验证顺序以及在用法文本中的显示顺序。
5.1.3.2 将参数设为必填项
IsRequired 将强制命令行参数为强制参数。如果未在可执行文件的命令行参数中为所需选项指定值,则会抛出 ChoCommandLineArgException。
5.1.3.3 提供默认值
为命令行参数提供默认值将允许解析器在命令行中未指定该参数时将此默认值分配给成员。请注意,设置此参数并不能阻止用户在命令行上指定不同的值,它只是在用户选择不提供值时提供默认值。
5.1.3.4 提供备用值
如果命令行参数已针对相关选项传递,但未能转换并分配给成员,则将备用值分配给成员。
5.1.3.5 为命令行参数指定别名
Aliases 属性命名命令行参数的别名。这些是命令行参数可能引用的其他名称。它是一个字符串属性,可以使用逗号或分号分隔指定多个名称。此处指定的任何别名必须在其他别名和命令行开关中是唯一的。解析器不会检查这些选项的名称唯一性。
5.1.3.6 格式化参数
这些参数是可选的,用于格式化并使其显示优雅的用法文本。以下是可用于格式化用法文本的参数
- NoOfTabsSwitchDescFormatSeperator - 可选。开关和描述之间放置的 TAB 字符数。默认为 1。
- DescriptionFormatLineSize - 可选。命令行开关描述行大小。默认为 60。
- DescriptionFormatLineBreakChar - 可选。命令行开关描述换行符。默认为空格 (' ') 字符。
5.1.4 ChoPositionalCommandLineArgAttribute
此属性可应用于类的字段和属性,以将其指定为位置命令行参数。此属性指定类的成员接收指定位置的命令行参数值。位置始终从 1 开始。
5.1.4.1 描述性参数
此属性中有三个描述性参数。
- Position - 必填。命令行参数位置。必须为 1 及以上的值。
- ShortName - 必填。开关的短名称,用于生成帮助文本。
除了上述描述性属性外,您还可以为此参数指定备用值、默认值、格式化参数。此参数不能指定别名。
6. 支持的类型
命令行参数解析器支持所有使用任何 CLR 数据类型定义的成员。没有任何限制。所有内置数据类型都由解析器自动管理,无需特殊的转换处理。以下是支持的内置类型
enum
bool
byte
sbyte
char
decimal
double
float
int
uint
long
ulong
short
ushort
字符串
如果在解析器转换和将命令行值分配给成员期间发生异常,它将抛出 ChoCommandLineArgException。
6.1 bool 值的特殊处理
本节说明了传递和处理命令行参数中布尔值的特殊方式。大多数命令行值可以以下列 开关:值 格式传递给可执行文件
清单 6.1 Test1.exe 带开关和值
>Test1.exe /name:"Raj" /msg:"Hello world"
但是布尔参数可以通过两种方式处理
6.1.1 显式方式
此处,布尔值以字符串值(True/False)的形式传递。此示例说明开关 -r 的值以 True 文本传递。解析器获取该值,转换并将其分配给相应的数据成员。
清单 6.2 Test1.exe 带显式布尔 TRUE 值
>Test1.exe /name:"Raj" /msg:"Hello world" /r:True
清单 6.3 Test1.exe 带显式布尔 FALSE 值
>Test1.exe /name:"Raj" /msg:"Hello world" /r:False
6.1.2 隐式方式
本节说明了如何在不显式传递值的情况下设置布尔值。解析器查找命令行参数中布尔参数的开关。如果指定了布尔开关(/r),解析器将其视为 True 值。如果布尔开关指定为(/r-),解析器将其视为 False 值。
清单 6.4 Test1.exe 带隐式布尔 TRUE 值
>Test1.exe /name:"Raj" /msg:"Hello world" /r
清单 6.5 Test1.exe 带隐式布尔 FALSE 值
>Test1.exe /name:"Raj" /msg:"Hello world" /r-
6.2 复杂数据类型成员的处理
本节说明如何处理复杂的用户定义数据类型成员。有多种方法可以接收、解析和将值分配给命令行参数成员。
- 回调机制
- 值转换器机制
6.2.1 回调机制
这是接收、解析和将命令行参数值加载到成员的最简单方法。这使您可以完全控制处理对象中任何类型的命令行参数值。重写命令行参数对象中的 OnBeforeCommandLineArgLoaded 方法,解析器将为每个命令行参数开关调用此方法。您可以在其中为相关成员编写自定义逻辑,并用值加载成员。一旦处理了情况,只需返回 True 以告知解析器您已处理了转换。
清单 6.4 带回调覆盖的 CommandLineArgObject
[ChoCommandLineArgObject(ApplicationName = "Hello world", Copyright = "Copyright 2014 Cinchoo Inc.")]
public class HelloWorldCmdLineParams : ChoCommandLineArgObject
{
[ChoCommandLineArg("name", Aliases="n", IsRequired = true, Description = "Name of the person.")]
public string Name;
[ChoCommandLineArg("msg", DefaultValue = "Good Morning", Description = "Greeting message")]
public string Message
{
get;
set;
}
[ChoCommandLineArg("s", ShortName = "<int | INFINITE>", Description = "Sleep period.")]
public int Sleep
{
get;
set;
}
protected override bool OnBeforeCommandLineArgLoaded(string memberName, ref string value, object defaultValue, object fallbackValue)
{
if (memberName == "Sleep")
{
if (value == null)
Sleep = 0;
else
{
if (String.Compare(value.ToString(), "INFINITE", true) == 0)
Sleep = -1;
else
{
int timeout = 0;
int.TryParse(value.ToString(), out timeout);
Sleep = timeout;
}
}
return true;
}
else
return base.OnBeforeCommandLineArgLoaded(memberName, ref value, defaultValue, fallbackValue);
}
}
在上面的示例中,Sleep 参数是 int 类型。但是它提供了选项,可以接受 int 或 INFINITE 值作为命令行参数。在回调机制中,我们通过重写 OnBeforeCommandLineArgLoaded 方法来处理它。
清单 6.5 Test1.exe 传入 Sleep 值
>Test1.exe /name:"Raj" /msg:"Hello world" /s:INFINITE Hello world [Version 1.0.0.0] Copyright 2014 Cinchoo Inc. -- ConsoleApplication2.HelloWorldCmdLineParams State -- Message: Hello world Sleep: -1 Name: Raj
6.2.2 值转换器机制
这是接收、解析和将命令行参数值加载到成员的替代方法。这为您提供了使用 ValueConverter 进行转换的机会。您可以选择使用现有转换器或创建新的转换器并使用它们。在这里,我将向您展示如何创建新转换器并在命令行参数成员中使用它们。这种方法允许您在可插拔架构中重用转换逻辑。
首先,让我们定义一个 ChoTimeoutConverter。 它将输入字符串值转换为 Timeout (int) 值。您可以定义从 System.Windows.Data.IValueConverter (PresentationFramework.dll) 或 Cinchoo.Core.IChoValueConverter (Cinchoo.Core.dll) 派生的转换器类。这两个接口具有相同的方法。您可以使用任何适合您需求的接口。
清单 6.6 ChoTimeoutConverter 类
public class ChoTimeoutConverter : IChoValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return 0;
int timeout = 0;
if (String.Compare("INFINITE", value.ToString(), true) == 0)
return -1;
else if (int.TryParse(value.ToString(), out timeout))
return timeout;
else
return 0;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value != null ? value.ToString() : String.Empty;
}
}
在上面,从 IChoValueConverter 接口定义了 ChoTimeoutConverter。实现了方法。它是自解释的。
现在我将说明如何在命令行参数成员中使用上述转换器。有几种方法可以在命令行参数对象中使用它们。
- 定义转换器属性并使用它
- 直接使用 ChoTypeConverterAttribute
6.2.2.1 定义转换器属性并使用它
这种方法将允许您为每个转换器定义转换器属性。下面的示例演示如何为 ChoTimeoutConverter 类定义 ChoTimeoutConverterAttribute。转换器属性必须从 ChoTypeConverterAttribute 类派生,并将转换器类型传递给其转换器。请参阅下面的示例
清单 6.7 ChoTimeoutConverterAttribute 类
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
public class ChoTimeoutConverterAttribute : ChoTypeConverterAttribute
{
public ChoTimeoutConverterAttribute()
: base(typeof(ChoTimeoutConverter1))
{
}
}
一旦按照上述方式定义了属性,就可以将其用于命令行参数成员,以执行参数值的转换,如下所示
清单 6.8 在成员中使用 ChoTimeoutConverterAttribute
[ChoCommandLineArgObject(ApplicationName = "Hello world", Copyright = "Copyright 2014 Cinchoo Inc.")]
public class HelloWorldCmdLineParams : ChoCommandLineArgObject
{
[ChoCommandLineArg("name", Aliases="n", IsRequired = true, Description = "Name of the person.")]
public string Name;
[ChoCommandLineArg("msg", DefaultValue = "Good Morning", Description = "Greeting message")]
public string Message
{
get;
set;
}
[ChoCommandLineArg("t", ShortName = "<int | INFINITE>", Description = "Timeout period.")]
[ChoTimeoutConverter]
public int Timeout
{
get;
set;
}
}
6.2.2.2 使用 ChoTypeConverterAttribute
这说明了如何直接将转换器类(ChoTimeoutConverter)用于命令行对象成员,而无需为每个转换器类定义转换器属性。Cinchoo 框架为此目的提供了通用属性类。它是 ChoTypeConverterAttribute。只需使用此属性并将 ChoTimeoutConverter 类型传递给其构造函数,如下所示。
清单 6.9 在成员中使用 ChoTypeConverterAttribute
[ChoCommandLineArgObject(ApplicationName = "Hello world", Copyright = "Copyright 2014 Cinchoo Inc.")]
public class HelloWorldCmdLineParams : ChoCommandLineArgObject
{
[ChoCommandLineArg("name", Aliases="n", IsRequired = true, Description = "Name of the person.")]
public string Name;
[ChoCommandLineArg("msg", DefaultValue = "Good Morning", Description = "Greeting message")]
public string Message
{
get;
set;
}
[ChoCommandLineArg("t", ShortName = "<int | INFINITE>", Description = "Timeout period.")]
[ChoTypeConverter(typeof(ChoTimeoutConverter))]
public int Timeout
{
get;
set;
}
}
到目前为止,您已经了解了如何使用各种方法解析、转换和将命令行参数值加载到其成员中。
6.3 枚举的特殊处理
本节说明了传递和处理命令行参数中枚举值的特殊方式。大多数命令行值可以以下列 开关:值 格式传递给可执行文件
清单 6.10 Test1.exe 带开关和值
>Test1.exe /name:"Raj" /msg:"Hello world"
我们首先定义枚举类型和带有枚举成员的命令行参数对象,如下所示
public enum Action { ADD, DEL, UPDATE };
[ChoCommandLineArgObject]
public class COMPUTERCmdLineArgObject : ChoCommandLineArgObject
{
[ChoPositionalCommandLineArg(1, "\\\\computername", IsRequired = true, Order = 0)]
public string ComputerName;
[ChoCommandLineArg("action", IsRequired = true)]
public Action ActionValue;
}
以上代码说明了定义了 Action 枚举。它由 COMPUTERCmdLineArgObject 类通过声明 ActionValue 成员来使用。它必须用 ChoCommandLineArgAttribute 声明。所有枚举类型都必须用 ChoCommandLineArgAttribute 修饰。
以下是测试运行,显示如何将枚举值作为命令行参数传递
清单 6.11 Test1.exe 带枚举值(隐式方式)
>Test1.exe "\\NYCDR1234234" /UPDATE
它说明了枚举值 可能 以 /[EnumValue] 格式传递。
清单 6.12 Test1.exe 带枚举值(显式方式)
>Test1.exe "\\NYCDR1234234" /action:UPDATE
它说明了枚举值 可能 以 /Switch:EnumValue 格式传递。
7. 自定义
可以通过多种方式自定义解析器,例如命令行开关字符、赋值分隔符、用法开关、开关大小写敏感性处理等。默认设置对于大多数应用程序来说应该足够好,但如果需要,它们可用于您的自定义。
7.1 指定开关字符
这是在将命令行参数传递给可执行文件时用于前缀开关的特殊字符。解析器默认带有开关字符 '/', '-'。 这意味着这些是可用于前缀开关的字符。可以通过打开 [appExe].config 或 App.config 文件来自定义,添加或编辑自定义配置节 'commandLineParserSettings'。
清单 7.1 CommandLineParserSettings 配置节
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="commandLineParserSettings" type="Cinchoo.Core.Shell.ChoCommandLineParserSettings, Cinchoo.Core" />
</configSections>
<commandLineParserSettings switchChars="/, -" valueSeperators = ":, =" />
</configuration>
Cinchoo.Core.Shell.ChoCommandLineParserSettings 是配置节对象。以下是可用于自定义解析器的参数
- switchChars - 可选。此处可指定可能的命令行开关字符列表。允许多个字符。必须指定一个字符。字符之间用逗号分隔。默认值:“/, -”。
- valueSeparators - 可选。指定可能的开关-值分隔符字符列表。可以指定多个字符。必须至少指定一个字符。字符之间用逗号分隔。默认值:":. ="。
- usageSwitches - 可选。这是用于显示用法文本的开关。指定可能的用法开关字符串列表。可以指定多个值。必须至少指定一个值。字符串之间用逗号分隔。默认值:"?、h、help"。
- fileArgSwitches - 可选。此开关用于指定包含命令行参数的文件路径。某些程序可能有很长的参数列表。为了避免重复向可执行文件传递命令行参数值,您可以将它们保存到文件中,然后使用此开关输入文件。可以指定多个值。必须至少有一个值。字符之间用逗号分隔。默认值:'@'。
- ignoreCase - 可选。True,命令行开关不区分大小写。否则为 false。默认值:True。
- showUsageIfEmpty - 可选。True,将显示详细的用法文本。否则为 false。默认值:True。
- doNotShowHeader - 可选。True,将显示标题信息,如 AssemblyTitle、Version 和 Description。否则为 false。默认值:True。
7.2 命令行开关的大小写敏感性
您可以通过 ChoCommandLineParserSettings 中的 ignoreCase 参数来指定命令行开关是否区分大小写。默认情况下,开关是不区分大小写的。
8. CommandLineObject 覆盖
本节说明了一些重要的可重写方法,以便自定义解析器。
8.1 GetUsage() 方法
通常,解析器在大多数情况下都会为您创建用法文本。在极少数情况下,您可能希望自定义用法文本的显示方式。在这种情况下,您可以重写 GetUsage() 方法。它是一个公共方法,返回字符串值。
8.2 OnBeforeCommandLineArgLoaded 方法
此方法在每个命令行参数值加载之前调用。在此方法中,您可以验证命令行值、执行转换甚至替换为新值等。返回 true,指示解析器停止处理该值。否则继续加载值的过程。
8.3 OnAfterCommandLineArgLoaded 方法
此方法在加载每个命令行参数时调用。在这里,您可以执行任何分配后任务,例如可以从该属性派生依赖属性值。
8.4 OnCommandLineArgLoadError 方法
当加载命令行参数到成员时发生异常时,会调用此方法。在此处,您可以执行异常处理。返回 true,指示解析器已处理异常。否则为 false。
8.5 OnBeforeCommandLineArgObjectLoaded 方法
此方法在命令行参数对象加载之前调用。在此方法中,您可以查看命令行参数的整体负载,执行一些预验证,甚至用新值替换值等。返回 true,指示解析器停止解析。否则继续加载对象的过程。
8.6 OnAfterCommandLineArgLoaded 方法
此方法在命令行参数对象加载之后调用。在这里,您可以选择执行任何赋值后任务,例如可以派生依赖属性值、验证等。
8.7 OnCommandLineArgObjectLoadError 方法
当解析和加载整个命令行参数对象时发生异常时,会调用此方法。在此处,您可以执行异常处理。返回 true,指示解析器已处理异常。否则为 false。
8.8 OnCommandLineArgNotFound 方法
当可执行文件的参数列表中没有找到命令行参数时,会调用此方法。
9. 高级主题
在本主题中,我将讨论一些关键的高级主题,以便在使用此解析器时理解和在项目中应用。它将帮助您了解如何在项目中有效利用解析器。
9.1 指定带空格的参数
在大多数情况下,不含任何空格的命令行参数值可以直接指定。如果值包含空格,则必须用双引号括起来。例如,
清单 9.1 Test1.exe 带有包含空格的值
>Test1.exe /name:"Raj Nagalngam" /msg:"Hello world" /r:True
9.2 在值中指定引号
默认情况下,双引号 (") 是唯一识别的引号。在引号内部,您可以转义引号字符本身,以将文字引号插入到值中。它可以按如下方式插入(使用额外的双引号转义)
清单 9.2 Test1.exe 带有包含双引号的值
>Test1.exe /name:"Raj""s msg" /msg:"Hello world" /r:True
9.3 从外部文件加载参数
一个程序可能有多个大型、复杂的命令行参数集,并且希望多次运行它们,在这种情况下,您可以将值保存到外部文件并将文件传递给程序。这样可以节省每次运行重新键入命令行参数值的时间和精力。
清单 9.2 Test1.exe 带有包含双引号的值
>Test1.exe @"C:\Sample\CmdLineArgs.txt"
10. 验证
在本节中,我将讨论如何验证每个命令行参数成员值、不同的验证方法等。任何接受命令行参数输入的应用程序都必须确保信息在您指定的一些规则集方面是有效的。例如,您可能需要检查客户的电话号码是否具有正确的位数,或者日期是否在特定范围内。此外,如果验证失败,您可能需要发送一条错误消息,解释错误所在。
Cinchoo 提供了一个类库,称为验证器,它提供用于验证命令行参数成员的代码。例如,一个验证器检查空字符串,另一个验证器检查字符串是否只包含特定字符集等。在某些情况下,您可能希望定义自己的自定义验证器并使用它们来验证成员值。
有一些特殊的验证器用于组合、聚合其他验证器并将它们分组到一个规则集中。
- ChoAndCompositeValidator - 它将其他验证器分组,此复合验证器中的所有验证器都必须为真才能成功验证。
- ChoOrCompositeValidator - 它将其他验证器分组,复合验证器中至少有一个验证器必须为真才能成功验证。
如果您想避免使用此库功能进行验证并自行控制验证,可以通过两种方式实现
- 回调机制 - OnAfterCommandLineArgLoaded 重写方法可用于放置自定义逻辑以验证命令行参数值。
- 属性设置器机制 - 这是另一个可以对这些成员值进行自定义验证的地方。
10.1 使用验证器
以下过程解释了如何在命令行参数对象成员中使用验证器。有两种方法可以为命令行参数成员使用验证器
- ChoValidatorAttribute - 一个通用验证器属性,用于特定验证器没有相应属性的情况。
- 验证器特定属性 - 这些是每个验证器的自定义验证器属性。例如,ChoStringValidatorAttribute 是 ChoStringValidator 类的属性。
Cinchoo 开箱即用支持以下验证器
- ChoValidators - Cinchoo 库本身提供的验证器。您可以在 Cinchoo.Core 命名空间下找到许多此类验证器。例如,ChoNotNullValidator、ChoNotNullOrEmptyValidator 等。
- BCL 配置验证器 - .NET BCL 库提供的验证器。您可以在 System.Configuration 命名空间中找到它们。例如,StringValidator、IntegerValidator 等。
- BCL DataAnnotation 验证器 - .NET BCL 库在 System.ComponentModel.DataAnnotations 命名空间下提供的另一组验证器。
10.1.1 使用 ChoValidatorAttribute
这是为命令行参数成员指定验证规则的一种方法。如果特定验证器没有可用的验证器属性,则此属性可用于解决此问题。此属性将验证器类型作为输入。验证器类型可以是以下派生类之一
- Cinchoo.Core.ChoValidator - Cinchoo 框架库提供了许多验证器供您在应用程序中使用。
- System.Configuration.ConfigurationValidatorBase (System.Configuration.dll) - 这些是 .NET BCL 提供的验证器。
以下是此属性可用的可选属性
- ConstructorArgs - 可选。大多数验证器通过构造函数接受一些强制参数,以对命令行对象成员执行验证。这些参数可以通过此属性指定。它接受 object[] 作为值。这些值是位置构造函数参数。
- ConstructorArgsText - 可选字符串值。构造函数参数可以指定为文本,每个值用 ';' 分隔。
- KeyValuePropertiesText - 可选字符串值。它是一个键值对,用 ';' 字符分隔以设置验证器属性值。例如,“MinValue=1;MaxValue=10”。
清单 10.1 带验证器的命令行参数对象
[ChoCommandLineArgObject(Description = "Utility to generate schema or class files from given source.")]
public sealed class ChoAppCmdLineParams : ChoCommandLineArgObject
{
[ChoPositionalCommandLineArg(1, "xmlfile", IsRequired = true, Description = "Name of an xml file to infer xsd schema from.")]
[ChoValidator(typeof(ChoNotNullOrWhiteSpaceValidator))]
[ChoValidator(typeof(StringValidator), ConstructorArgsText = "10")]
public string XmlFilePath
{
get;
set;
}
[ChoCommandLineArg("o", Description = "The output directory to create files in. The default is the current directory.")]
[ChoStringValidator(MinLength = 10)]
[ChoContainsCharactersValidator("A")]
public string OutputDirectory
{
get;
set;
}
}
在上面的示例中,成员 'XmlFilePath' 指定了 2 个验证。它必须不为空 且 必须包含最少 10 个字符。该示例演示了如何使用 ChoValidatorAttribute 来定义没有相应自定义验证器属性的验证器。请注意,顶层指定的多个验证器默认情况下会组合并作为 AND 条件进行验证。验证顺序不保证按顺序执行。
'OutputDirectory' 成员用与验证器对应的自定义验证器属性进行修饰。在此处,它用 ChoStringValidatorAttribute 和 ChoContainsCharatersValidatorAttribute 修饰。它在声明验证器时提供了灵活性、简单性和类型安全性。
创建一个控制台应用程序并创建 ChoAppCmdLineParams 对象,如下所示
清单 10.2 Main 方法
class Program
{
static void Main(string[] args)
{
ChoAppCmdLineParams cmdLineParams = new ChoAppCmdLineParams();
Console.WriteLine(cmdLineParams.ToString());
}
}
下面列出了程序使用不同参数的测试运行
清单 10.3 Test1.exe 没有参数
>Test1.exe ConsoleApplication2 [Version 1.0.0.0] Copyright c 2014 Utility to generate schema or class files from given source. Found exception while loading `xmlfile` command line argument. The string must be at least 10 characters long. ConsoleApplication2.exe xmlfile [/o:<string>] xmlfile Name of an xml file to infer xsd schema from. /o The output directory to create files in. The default is the current directory. Press any key to continue . . .
在上述运行中,可执行文件在没有传递任何命令行参数的情况下运行。应用程序正在尝试实例化 ChoAppCmdLineParams 对象。在创建此类对象时,框架会尝试验证成员值。在这种情况下,位置命令行参数 'xmlFilePath' 验证失败。应用程序以异常终止。
清单 10.4 Test1.exe 带有不正确的输出目录值
>Test1.exe "C:\Windows\Systems\cpanal.xml" /o:"C:\Windows\Systems\Xcpanal.xml" ConsoleApplication2 [Version 1.0.0.0] Copyright c 2014 Utility to generate schema or class files from given source. Found exception while loading `o` command line argument. The value must contains ALL of the 'A' characters. ConsoleApplication2.exe xmlfile [/o:<string>] xmlfile Name of an xml file to infer xsd schema from. /o The output directory to create files in. The default is the current directory. Press any key to continue . . .
在上述测试运行中,可执行文件带参数运行。位置参数 'XmlFilePath' 通过了验证(不为 null AND 包含超过 10 个字符)。但它在验证 'OutputDirectory' 时失败。它不包含字符 'A'。应用程序以异常终止。
清单 10.5 Test1.exe 带有正确的值
>Test1.exe "C:\Windows\Systems\cpanal.xml" /o:"C:\Windows\Systems\Acpanal.xml" ConsoleApplication2 [Version 1.0.0.0] Copyright c 2014 Utility to generate schema or class files from given source. -- ConsoleApplication2.ChoAppCmdLineParams1 State -- XmlFilePath: C:\Windows\Systems\cpanal.xml OutputDirectory: C:\Windows\Systems\Acpanal.xml Press any key to continue . . .
在上述测试运行中,可执行文件带有效参数运行。位置参数 'XmlFilePath' 和 'OutputDirectory' 都通过了验证,没有出现任何错误。
10.1.2 使用自定义验证器属性
上一节我谈到了在命令行参数成员上使用通用验证器属性来定义验证。它为在没有验证器属性的情况下使用验证器铺平了道路。一些验证器附带自定义验证器属性。它简单明了,易于使用且类型安全。在下面的示例中,OutputDirectory 成员定义了 2 个带有其自定义属性的验证器。
清单 10.6 带验证器的命令行参数对象
[ChoCommandLineArgObject(Description = "Utility to generate schema or class files from given source.")]
public sealed class ChoAppCmdLineParams : ChoCommandLineArgObject
{
[ChoPositionalCommandLineArg(1, "xmlfile", IsRequired = true, Description = "Name of an xml file to infer xsd schema from.")]
[ChoValidator(typeof(ChoNotNullOrWhiteSpaceValidator))]
[ChoValidator(typeof(StringValidator), ConstructorArgsText = "10")]
public string XmlFilePath
{
get;
set;
}
[ChoCommandLineArg("o", Description = "The output directory to create files in. The default is the current directory.")]
[ChoStringValidator(MinLength = 10)]
[ChoContainsCharactersValidator("A")]
public string OutputDirectory
{
get;
set;
}
}
10.2 回调机制
如果您想对成员执行一些复杂的验证,可以使用此机制。只需在命令行类中重写 OnAfterCommandLineArgLoaded 方法,如下所示
清单 10.6 带自定义验证的命令行参数对象
[ChoCommandLineArgObject(Description = "Utility to generate schema or class files from given source.")]
public sealed class ChoAppCmdLineParams1 : ChoCommandLineArgObject
{
[ChoPositionalCommandLineArg(1, "xmlfile", IsRequired = true, Description = "Name of an xml file to infer xsd schema from.")]
[ChoValidator(typeof(ChoNotNullOrWhiteSpaceValidator))]
[ChoValidator(typeof(StringValidator), ConstructorArgsText = "10")]
public string XmlFilePath
{
get;
set;
}
[ChoCommandLineArg("o", Description = "The output directory to create files in. The default is the current directory.")]
[ChoStringValidator(MinLength = 10)]
[ChoContainsCharactersValidator("A")]
public string OutputDirectory
{
get;
set;
}
protected override void OnAfterCommandLineArgLoaded(string memberName, object value)
{
if (memberName == "OutputDirectory")
{
if (!((string)value).StartsWith(@"C:\"))
throw new ArgumentException("Invalid directory passed.");
}
else
base.OnAfterCommandLineArgLoaded(memberName, value);
}
}
在上面的示例代码中,展示了如何使用回调机制验证成员。如果 'OutputDirectory' 成员值不是以 'C:\' 开头,则会抛出异常。
清单 10.7 Test1.exe 带有不正确的输出目录值
>Test1.exe "C:\Windows\Systems\cpanal.xml" /o:"D:\Windows\Systems\Xcpanal.xml" ConsoleApplication2 [Version 1.0.0.0] Copyright c 2014 Utility to generate schema or class files from given source. Found exception while loading `o` command line argument. Invalid directory passed. ConsoleApplication2.exe xmlfile [/o:<string>] xmlfile Name of an xml file to infer xsd schema from. /o The output directory to create files in. The default is the current directory. Press any key to continue . . .
如果使用上述参数值运行示例,则 'OutputDirectory' 成员的验证将失败并抛出异常 'Invalid directory passed.'。
10.3 属性设置器机制
这是另一种对成员执行复杂验证的方法。它的方法与回调机制完全相同。在这里,可以在属性设置器中对属性命令行成员进行验证。请看下面的示例
清单 10.8 带自定义验证的命令行参数对象
[ChoCommandLineArgObject(Description = "Utility to generate schema or class files from given source.")]
public sealed class ChoAppCmdLineParams1 : ChoCommandLineArgObject
{
[ChoPositionalCommandLineArg(1, "xmlfile", IsRequired = true, Description = "Name of an xml file to infer xsd schema from.")]
[ChoValidator(typeof(ChoNotNullOrWhiteSpaceValidator))]
[ChoValidator(typeof(StringValidator), ConstructorArgsText = "10")]
public string XmlFilePath
{
get;
set;
}
private string _outputDirectory;
[ChoCommandLineArg("o", Description = "The output directory to create files in. The default is the current directory.")]
[ChoStringValidator(MinLength = 10)]
[ChoContainsCharactersValidator("A")]
public string OutputDirectory
{
get { return _outputDirectory; }
set
{
if (!value.StartsWith(@"C:\"))
throw new ArgumentException("Invalid directory passed.");
_outputDirectory = value;
}
}
}
在上面的示例代码中,展示了如何使用属性设置器机制验证成员。'OutputDirectory' 属性的验证在属性设置器中处理。如果值不是以 'C:\' 开头,则会抛出异常。
清单 10.9 Test1.exe 带有不正确的输出目录值
>Test1.exe "C:\Windows\Systems\cpanal.xml" /o:"D:\Windows\Systems\Xcpanal.xml" ConsoleApplication2 [Version 1.0.0.0] Copyright c 2014 Utility to generate schema or class files from given source. Found exception while loading `o` command line argument. Invalid directory passed. ConsoleApplication2.exe xmlfile [/o:<string>] xmlfile Name of an xml file to infer xsd schema from. /o The output directory to create files in. The default is the current directory. Press any key to continue . . .
如果使用上述参数值运行示例,则 'OutputDirectory' 成员的验证将失败并抛出异常 'Invalid directory passed.'。
11. 命令行对象构建器 (分组)
到目前为止,我们已经学习了如何在应用程序中定义和使用单个命令行参数对象。它最适合具有单个功能和参数的应用程序。有些应用程序执行多种功能,并带有自己的参数。例如,您有一个应用程序处理各种输入数据(网络、文件、互联网等)的数据,这些数据需要各自的参数。这意味着需要某种工厂,您可以在其中定义这些上下文。基本上,第一个参数将定义要查找的上下文(网络、文件、互联网等),然后任何后续参数将仅充当该特定上下文的参数。
'NET' dos 命令是此场景的完美示例。如果输入 'net',将产生以下结果
c:\>net The syntax of this command is: NET [ ACCOUNTS | COMPUTER | CONFIG | CONTINUE | FILE | GROUP | HELP | HELPMSG | LOCALGROUP | PAUSE | SESSION | SHARE | START | STATISTICS | STOP | TIME | USE | USER | VIEW ]
c:\>net ACCOUNTS /? The syntax of this command is: NET ACCOUNTS [/FORCELOGOFF:{minutes | NO}] [/MINPWLEN:length] [/MAXPWAGE:{days | UNLIMITED}] [/MINPWAGE:days] [/UNIQUEPW:number] [/DOMAIN]
11.1 定义命令行参数构建器
首先定义命令行对象构建器,如下所示
清单 11.1 命令行参数构建器对象
[ChoCommandLineArgBuilder]
public class NetCmdBuilder : ChoCommandLineArgBuilder
{
[ChoCommandLineArgBuilderCommand("START", typeof(STARTCmdLineArgObject), Order = 0)]
[ChoCommandLineArgBuilderCommand("STOP", typeof(STOPCmdLineArgObject), Order = 1)]
[ChoCommandLineArgBuilderCommand("COMPUTER", typeof(COMPUTERCmdLineArgObject), Order = -1)]
public NetCmdBuilder()
{
}
}
上面的代码演示了如何定义命令行对象构建器对象。首先,从 ChoCommandLineArgBuilder 类定义一个构建器类(例如 NetCmdBuilder),它表示此对象是一个命令行参数构建器对象。并且它必须用 ChoCommandLineArgBuilderAttribute 修饰才能完成定义。除此之外,我们需要在构建器的默认构造函数中使用 ChoCommandLineArgBuilderCommandAttribute 开始定义命令映射。在上面的示例中,构建器定义了 3 个命令 START、STOP 和 COMPUTER,分别映射到 STARTCmdLineArgObject、STOPCmdLineArgObject 和 COMPUTERCmdLineArgObject。 属性中的 order 描述了命令在用法文本中的显示顺序。
清单 11.2 COMPUTERCmdLineArgObject
public enum Action { ADD, DEL };
[ChoCommandLineArgObject(DoNotShowUsageDetail = true)]
public class COMPUTERCmdLineArgObject : ChoCommandLineArgObject
{
[ChoPositionalCommandLineArg(1, "\\\\computername", IsRequired = true, Order = 0)]
public string ComputerName;
[ChoCommandLineArg("action", IsRequired = true)]
public Action Action;
}
上面的命令行参数包含两个成员:ComputerName - 位置必填参数和 Action - 必填枚举参数。注意,DoNotShowUsageDetail 为 true 告诉框架不要在用法文本中显示每个成员参数的详细信息。
清单 11.3 STARTCmdLineArgObject
[ChoCommandLineArgObject] public class STARTCmdLineArgObject : ChoCommandLineArgObject { [ChoPositionalCommandLineArg(1, "service")] public string ServiceName; }
清单 11.4 STOPCmdLineArgObject
[ChoCommandLineArgObject(DoNotShowUsageDetail = true)] public class STOPCmdLineArgObject : ChoCommandLineArgObject { [ChoPositionalCommandLineArg(1, "service", IsRequired = true)] public string ServiceName; }
清单 11.5 Main 方法
class Program
{
static void Main(string[] args)
{
NetCmdBuilder netCmdBuilder = new NetCmdBuilder();
Console.WriteLine(netCmdBuilder.CommandLineArgObject.ToString());
}
}
我们首先创建 netCmdBuilder 对象的新实例。就是这样。框架在幕后完成了大部分工作。参数成功加载后,构建器对象的 CommandLineArgObject 成员将根据作为参数传递给可执行文件的上下文加载匹配的命令对象。
下面列出了程序使用不同参数集及其输出的测试运行。
清单 11.6 net.exe 没有参数
c:\>net The syntax of this command is: NET [COMPUTER | START | STOP] Press any key to continue . . .
清单 11.7 net.exe 带有 COMPUTER 上下文,未传递计算机名
c:\>net COMPUTER
Missing '\\computername' argument.
NET COMPUTER \\computername {/ADD | /DEL}
Press any key to continue . . .
清单 11.7 net.exe 带有 COMPUTER 上下文,带有有效参数
c:\>net COMPUTER \\NYC123453 /DEL -- CommadLineObjectBuilderSample.COMPUTERCmdLineArgObject State -- ComputerName: \\NYC123453 Action: DEL Press any key to continue . . .
在上述示例成功运行中,netCmdBuilder.CommandLineArgObject 填充了 COMPUTERCmdLineArgObject 对象的实例。
11.2 属性
11.2.1 ChoCommandLineArgObjectAttribute
此属性应用于将构造传递上下文的命令行参数对象并用命令行参数加载它们的类。它包含与 ChoCommandLineArgObjectAttribute 相同的一组属性。请参阅该部分。
11.2.2 ChoCommandLineArgBuilderCommandAttribute
此属性应用于构建器类的构造函数,以定义命令与命令行参数类之间的映射。可以使用多个属性来定义映射。
清单 11.8 示例命令行构建器对象
[ChoCommandLineArgBuilder]
public class NetCmdBuilder : ChoCommandLineArgBuilder
{
[ChoCommandLineArgBuilderCommand("START", typeof(STARTCmdLineArgObject), Order = 0)]
[ChoCommandLineArgBuilderCommand("STOP", typeof(STOPCmdLineArgObject), Order = 1)]
[ChoCommandLineArgBuilderCommand("COMPUTER", typeof(COMPUTERCmdLineArgObject), Order = -1)]
public NetCmdBuilder()
{
}
}
上面的代码说明了使用 ChoCommandLineArgBuildCommandAttribute 定义了三个命令的构造函数。
- Command - 必填。命令名称。
- CommandType - 必填。命令行参数对象类型。
- Order - 可选,用于在用法文本中显示命令的顺序。
11.3 覆盖
11.2.2 GetCommandLineArgObjectType()
此方法可以被重写,以控制发现传递命令的命令类型。通常,所有映射都使用构建器类中的 ChoCommandLineArgBuildCommandAttribute 完成。有时您可能希望通过重写此方法来避免这样做。
[ChoCommandLineArgBuilder]
public class ChoNETCommandLineArgBuilder : ChoCommandLineArgBuilder
{
[ChoCommandLineArgBuilderCommand("ACCOUNTS", typeof(ChoAppCmdLineParams))]
public ChoNETCommandLineArgBuilder()
{
}
public override Type GetCommandLineArgObjectType(string command)
{
if (command == "COMPUTER")
return typeof(COMPUTERCmdLineArgObject);
else
return base.GetCommandLineArgObjectType(command);
}
}
上面的代码演示了如何重写 GetCommandLineArgObjectType 方法。