在C#中解析命令行参数的最佳方法?

在构建接受参数的控制台应用程序时,您可以使用传递给Main(string[] args)的参数。

在过去,我只是对该数组进行索引/循环并执行一些正则表达式来提取值。然而,当命令变得更加复杂时,解析会变得非常丑陋。

所以我感兴趣的是:

  • 您使用的库
  • 你使用的模式

假设命令始终遵守通用标准,例如在这里回答

625218 次浏览

我喜欢那一个,因为你可以为参数“定义规则”,无论是否需要,…

或者如果你是一个Unix爱好者,那么你可能会喜欢GNU Getopt. NET端口。

WPF TestApi库附带了用于C#开发的最好的命令行解析器之一。我强烈建议从Ivo Manolov关于API的博客开始查看它:

// EXAMPLE #2:
// Sample for parsing the following command-line:
// Test.exe /verbose /runId=10
// This sample declares a class in which the strongly-
// typed arguments are populated
public class CommandLineArguments
{
bool? Verbose { get; set; }
int? RunId { get; set; }
}


CommandLineArguments a = new CommandLineArguments();
CommandLineParser.ParseArguments(args, a);

http://www.codeplex.com/commonlibrarynet有一个命令行参数解析器

它可以使用
解析参数 1.属性
2.显式调用
3.单行多个参数或字符串数组

它可以处理以下内容:

-配置: Qa-起始日期:${今天}-地区:'New York'设置01

它非常容易使用。

这是我基于NovellOptions类编写的处理程序。

这是针对执行while (input !="exit")风格循环的控制台应用程序,例如FTP控制台等交互式控制台。

示例用法:

static void Main(string[] args)
{
// Setup
CommandHandler handler = new CommandHandler();
CommandOptions options = new CommandOptions();


// Add some commands. Use the v syntax for passing arguments
options.Add("show", handler.Show)
.Add("connect", v => handler.Connect(v))
.Add("dir", handler.Dir);


// Read lines
System.Console.Write(">");
string input = System.Console.ReadLine();


while (input != "quit" && input != "exit")
{
if (input == "cls" || input == "clear")
{
System.Console.Clear();
}
else
{
if (!string.IsNullOrEmpty(input))
{
if (options.Parse(input))
{
System.Console.WriteLine(handler.OutputMessage);
}
else
{
System.Console.WriteLine("I didn't understand that command");
}


}


}


System.Console.Write(">");
input = System.Console.ReadLine();
}
}

以及来源:

/// <summary>
/// A class for parsing commands inside a tool. Based on Novell Options class (http://www.ndesk.org/Options).
/// </summary>
public class CommandOptions
{
private Dictionary<string, Action<string[]>> _actions;
private Dictionary<string, Action> _actionsNoParams;


/// <summary>
/// Initializes a new instance of the <see cref="CommandOptions"/> class.
/// </summary>
public CommandOptions()
{
_actions = new Dictionary<string, Action<string[]>>();
_actionsNoParams = new Dictionary<string, Action>();
}


/// <summary>
/// Adds a command option and an action to perform when the command is found.
/// </summary>
/// <param name="name">The name of the command.</param>
/// <param name="action">An action delegate</param>
/// <returns>The current CommandOptions instance.</returns>
public CommandOptions Add(string name, Action action)
{
_actionsNoParams.Add(name, action);
return this;
}


/// <summary>
/// Adds a command option and an action (with parameter) to perform when the command is found.
/// </summary>
/// <param name="name">The name of the command.</param>
/// <param name="action">An action delegate that has one parameter - string[] args.</param>
/// <returns>The current CommandOptions instance.</returns>
public CommandOptions Add(string name, Action<string[]> action)
{
_actions.Add(name, action);
return this;
}


/// <summary>
/// Parses the text command and calls any actions associated with the command.
/// </summary>
/// <param name="command">The text command, e.g "show databases"</param>
public bool Parse(string command)
{
if (command.IndexOf(" ") == -1)
{
// No params
foreach (string key in _actionsNoParams.Keys)
{
if (command == key)
{
_actionsNoParams[key].Invoke();
return true;
}
}
}
else
{
// Params
foreach (string key in _actions.Keys)
{
if (command.StartsWith(key) && command.Length > key.Length)
{


string options = command.Substring(key.Length);
options = options.Trim();
string[] parts = options.Split(' ');
_actions[key].Invoke(parts);
return true;
}
}
}


return false;
}
}

Genghis命令行解析器可能有点过时,但它的功能非常完整,对我来说效果很好。

不久前我写了一个C#命令行参数解析器。它位于:http://www.codeplex.com/CommandLineArguments

我强烈建议使用配置项需求文档)和/或选项类型(相同的API,不同的命名空间)。例子从留档

bool show_help = false;
List<string> names = new List<string> ();
int repeat = 1;


var p = new OptionSet () {
{ "n|name=", "the {NAME} of someone to greet.",
v => names.Add (v) },
{ "r|repeat=",
"the number of {TIMES} to repeat the greeting.\n" +
"this must be an integer.",
(int v) => repeat = v },
{ "v", "increase debug message verbosity",
v => { if (v != null) ++verbosity; } },
{ "h|help",  "show this message and exit",
v => show_help = v != null },
};


List<string> extra;
try {
extra = p.Parse (args);
}
catch (OptionException e) {
Console.Write ("greet: ");
Console.WriteLine (e.Message);
Console.WriteLine ("Try `greet --help' for more information.");
return;
}

这个问题有很多解决方案。为了完整性,如果有人愿意,我将为我的google代码库中的两个有用类添加这个答案。

第一个是ArgumentList,它只负责解析命令行参数。它收集由开关“/x: y”或“-x=y”定义的名称-值对,还收集“未命名”条目的列表。它是基本的用法在这里讨论在这里查看课程

第二部分是命令解释器,它从您的. Net类创建了一个功能齐全的命令行应用程序。作为示例:

using CSharpTest.Net.Commands;
static class Program
{
static void Main(string[] args)
{
new CommandInterpreter(new Commands()).Run(args);
}
//example ‘Commands’ class:
class Commands
{
public int SomeValue { get; set; }
public void DoSomething(string svalue, int ivalue)
{ ... }

使用上面的示例代码,您可以运行以下命令:

Program.exe“字符串值”5

--或者--

Program.exedocomeThings /ivalue=5-svalue:"string value"

它就像那样简单,也可以像你需要的那样复杂。您可以查看源代码查看帮助下载二进制

看起来每个人都有自己的宠物命令行解析器,我最好也添加我的:)。

http://bizark.codeplex.com/

这个库包含一个命令行解析器,它将使用命令行中的值初始化一个类。它有大量的功能(我多年来一直在构建它)。

留档

BizArk框架中的命令行解析具有以下关键特性:

  • 自动初始化:类属性是根据命令行参数自动设置的。
  • 默认属性:在不指定属性名称的情况下发送一个值。
  • 价值转换:使用BizArk中包含的强大的ConvertEx类将值转换为正确的类型。
  • 布尔标志:标志可以通过简单地使用参数(例如, /b为true, /b-为false)或通过添加值true/false,yes/no等来指定。
  • 参数数组:只需在命令行名称后添加多个值即可设置定义为数组的属性。例如, /x1 2 3将使用数组{1,2,3}填充x(假设x定义为整数数组)。
  • 命令行别名:属性可以支持多个命令行别名。例如,帮助使用别名?。
  • 部分名称识别:您不需要拼出全名或别名,只需拼写足够让解析器将属性/别名与其他属性/别名区分开来。
  • 支持ClickOne:可以初始化属性,即使它们被指定为ClickOne部署应用程序的URL中的查询字符串。命令行初始化方法将检测它是否以ClickOne身份运行,因此您的代码在使用它时不需要更改。
  • 自动创建/?帮助:这包括考虑到控制台宽度的漂亮格式。
  • 加载/保存命令行参数到文件:如果您有多个要多次运行的大型复杂命令行参数集,这尤其有用。

我建议使用开源库CSharpOptParse。它解析命令行并用命令行输入水合用户定义的。NET对象。在编写C#控制台应用程序时,我总是转向这个库。

我个人最喜欢的是Peter Palotas的http://www.codeproject.com/KB/recipes/plossum_commandline.aspx

[CommandLineManager(ApplicationName="Hello World",
Copyright="Copyright (c) Peter Palotas")]
class Options
{
[CommandLineOption(Description="Displays this help text")]
public bool Help = false;


[CommandLineOption(Description = "Specifies the input file", MinOccurs=1)]
public string Name
{
get { return mName; }
set
{
if (String.IsNullOrEmpty(value))
throw new InvalidOptionValueException(
"The name must not be empty", false);
mName = value;
}
}


private string mName;
}

我最近遇到了FubuCore命令行解析实现我真的很喜欢它,原因是:

  • 它易于使用-虽然我找不到留档,但FubuCore解决方案还提供了一个项目,其中包含一组很好的单元测试,比任何留档都更能说明功能
  • 它有一个很好的面向对象的设计,没有代码重复或其他类似的东西,我曾经在我的命令行解析应用程序
  • 它是声明性的:你基本上为命令和参数集编写类,并用属性装饰它们以设置各种选项(例如名称、描述、强制/可选)
  • 库甚至打印一个漂亮的用法图,基于这些定义

下面是一个关于如何使用它的简单示例。为了说明用法,我编写了一个包含两个命令的简单实用程序: -add(将对象添加到列表中-对象由名称(字符串)、值(int)和布尔标志组成) -list(列出所有当前添加的对象)

首先,我为“add”命令编写了一个Command类:

[Usage("add", "Adds an object to the list")]
[CommandDescription("Add object", Name = "add")]
public class AddCommand : FubuCommand<CommandInput>
{
public override bool Execute(CommandInput input)
{
State.Objects.Add(input); // add the new object to an in-memory collection


return true;
}
}

这个命令接受一个命令输入实例作为参数,所以我接下来定义它:

public class CommandInput
{
[RequiredUsage("add"), Description("The name of the object to add")]
public string ObjectName { get; set; }


[ValidUsage("add")]
[Description("The value of the object to add")]
public int ObjectValue { get; set; }


[Description("Multiply the value by -1")]
[ValidUsage("add")]
[FlagAlias("nv")]
public bool NegateValueFlag { get; set; }
}

下一个命令是'list',实现如下:

[Usage("list", "List the objects we have so far")]
[CommandDescription("List objects", Name = "list")]
public class ListCommand : FubuCommand<NullInput>
{
public override bool Execute(NullInput input)
{
State.Objects.ForEach(Console.WriteLine);


return false;
}
}

'list'命令没有参数,所以我为此定义了一个NullInput类:

public class NullInput { }

现在剩下的就是在Main()方法中连接它,如下所示:

    static void Main(string[] args)
{
var factory = new CommandFactory();
factory.RegisterCommands(typeof(Program).Assembly);


var executor = new CommandExecutor(factory);


executor.Execute(args);
}

该程序按预期工作,在任何命令无效的情况下打印有关正确用法的提示:

  ------------------------
Available commands:
------------------------
add -> Add object
list -> List objects
------------------------

以及“add”命令的示例用法:

Usages for 'add' (Add object)
add <objectname> [-nv]


-------------------------------------------------
Arguments
-------------------------------------------------
objectname -> The name of the object to add
objectvalue -> The value of the object to add
-------------------------------------------------


-------------------------------------
Flags
-------------------------------------
[-nv] -> Multiply the value by -1
-------------------------------------

请使用apache Commons cli API的. net端口。这很棒。

以及用于概念和介绍的原始API

一个非常简单易用的用于命令行解析的临时类,支持默认参数。

class CommandLineArgs
{
public static CommandLineArgs I
{
get
{
return m_instance;
}
}


public  string argAsString( string argName )
{
if (m_args.ContainsKey(argName)) {
return m_args[argName];
}
else return "";
}


public long argAsLong(string argName)
{
if (m_args.ContainsKey(argName))
{
return Convert.ToInt64(m_args[argName]);
}
else return 0;
}


public double argAsDouble(string argName)
{
if (m_args.ContainsKey(argName))
{
return Convert.ToDouble(m_args[argName]);
}
else return 0;
}


public void parseArgs(string[] args, string defaultArgs )
{
m_args = new Dictionary<string, string>();
parseDefaults(defaultArgs );


foreach (string arg in args)
{
string[] words = arg.Split('=');
m_args[words[0]] = words[1];
}
}


private void parseDefaults(string defaultArgs )
{
if ( defaultArgs == "" ) return;
string[] args = defaultArgs.Split(';');


foreach (string arg in args)
{
string[] words = arg.Split('=');
m_args[words[0]] = words[1];
}
}


private Dictionary<string, string> m_args = null;
static readonly CommandLineArgs m_instance = new CommandLineArgs();
}


class Program
{
static void Main(string[] args)
{
CommandLineArgs.I.parseArgs(args, "myStringArg=defaultVal;someLong=12");
Console.WriteLine("Arg myStringArg  : '{0}' ", CommandLineArgs.I.argAsString("myStringArg"));
Console.WriteLine("Arg someLong     : '{0}' ", CommandLineArgs.I.argAsLong("someLong"));
}
}

我真的很喜欢命令行解析器库(http://commandline.codeplex.com/)。它通过属性设置参数的方式非常简单优雅:

class Options
{
[Option("i", "input", Required = true, HelpText = "Input file to read.")]
public string InputFile { get; set; }


[Option(null, "length", HelpText = "The maximum number of bytes to process.")]
public int MaximumLenght { get; set; }


[Option("v", null, HelpText = "Print details during execution.")]
public bool Verbose { get; set; }


[HelpOption(HelpText = "Display this help screen.")]
public string GetUsage()
{
var usage = new StringBuilder();
usage.AppendLine("Quickstart Application 1.0");
usage.AppendLine("Read user manual for usage instructions...");
return usage.ToString();
}
}

你可能喜欢我的橄榄球厘米

易于使用且可扩展的命令行参数解析器。处理:布尔、加/减、字符串、字符串列表、CSV、枚举。

内置“/?”帮助模式。

内置“/??”和“/? D”文档生成器模式。

static void Main(string[] args)
{
// create the argument parser
ArgumentParser parser = new ArgumentParser("ArgumentExample", "Example of argument parsing");


// create the argument for a string
StringArgument StringArg = new StringArgument("String", "Example string argument", "This argument demonstrates string arguments");


// add the argument to the parser
parser.Add("/", "String", StringArg);


// parse arguemnts
parser.Parse(args);


// did the parser detect a /? argument
if (parser.HelpMode == false)
{
// was the string argument defined
if (StringArg.Defined == true)
{
// write its value
RC.WriteLine("String argument was defined");
RC.WriteLine(StringArg.Value);
}
}
}

编辑:这是我的项目,因此这个答案不应该被视为第三方的认可。也就是说,我确实在我编写的每个基于命令行的程序中都使用它,它是开源的,我希望其他人可以从中受益。

CLAP(命令行参数解析器)有一个可用的API,并且有很好的文档记录。你创建一个方法,注释参数。https://github.com/adrianaisemberg/CLAP

PowerShell命令。

PowerShell根据命令小程序上指定的属性进行解析,支持验证、参数集、流水线、错误报告、帮助,最重要的是返回. NET对象以供在其他命令小程序中使用。

我发现一些有用的链接开始:

C#CLI是我编写的一个非常简单的命令行参数解析库。它有很好的文档记录和开源。