Hello World
Spiga

在简单控制台程序中获取并使用参数

2009-05-24 23:12 by 老赵, 22138 visits

需求描述

从命令行接受参数是编写命令行程序时最常见的事情之一。从命令行读取参数往往要求:

  • 允许多个同名参数
  • 参数不区分大小写
  • 提供参数别名(例如t等价于top)
  • 提供参数默认值

在简单的控制台应用程序中,一般可以使用本文的代码片断进行开发辅助开发。

命令行输入参数格式

本文中的代码片断可用于解析以下的格式的参数输入:

mycmd.exe /arg1:value1 /arg2:value2 /arg3:value3 ...

收集参数

在控制台程序中,可以使用如下代码进行参数收集:

static NameValueCollection ParseArguments(string[] args)
{
    var arguments = new NameValueCollection();
    foreach (string a in args)
    {
        int index = a.IndexOf(":");
        string argName = a.Substring(1, index - 1);
        string argValue = a.Substring(index + 1);

        arguments.Add(argName.ToLowerInvariant(), argValue);
    }

    return arguments;
}

以上方法将返回一个NameValueCollection对象,天生满足不区分大小写允许同名参数的需求。

使用参数

我们可以使用如下方式获取处理后的参数集合:

static void Main(string[] args)
{
    var arguments = ParseArguments(args);
    ...
}

如果要获取同名参数的所有值,则可以:

var values = arguments.GetValues("arg1");

如果参数有别名,则可以:

var value = arguments["top"] ?? argument["t"];

如果参数有默认值,则可以:

var value = Int32.Parse(arguments["top"] ?? "30");

注意事项

本文中的代码只适用于简单控制台程序,参数变化复杂的控制台程序则需要使用独立的参数输入模块负责参数的解析和控制。

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

26 条回复

  1. James.Ying
    *.*.*.*
    链接

    James.Ying 2009-05-24 23:19:00

    嘿嘿,支持一下

  2. Nick Wang (懒人王)
    *.*.*.*
    链接

    Nick Wang (懒人王) 2009-05-24 23:20:00

    确实很简单

  3. 老赵
    admin
    链接

    老赵 2009-05-24 23:33:00

    --引用--------------------------------------------------
    Nick Wang (懒人王): 确实很简单
    --------------------------------------------------------
    是简单地无法再简单了。

  4. Anders Cui
    *.*.*.*
    链接

    Anders Cui 2009-05-24 23:37:00

    难得老赵写点简单的东西:)

  5. 老赵
    admin
    链接

    老赵 2009-05-24 23:41:00

    @Anders Cui
    因为……其实是……那个……下一篇文章里要引用一下……所以……也为了方便日后查询……嘿嘿……

  6. wingoo
    *.*.*.*
    链接

    wingoo 2009-05-24 23:49:00

    在用这个,还不错
    http://consolefx.codeplex.com/

  7. 老赵
    admin
    链接

    老赵 2009-05-25 00:31:00

    @wingoo
    好东西。所以说,还是什么都要说,什么都要交流啊。
    你看又让我知道一个东西。
    真不知道为啥有些朋友就喜欢说,这个没资格,那么没必要,呵呵。

  8. 技术爱好者
    *.*.*.*
    链接

    技术爱好者 2009-05-25 07:00:00

    --引用--------------------------------------------------
    Jeffrey Zhao: @Anders Cui
    因为……其实是……那个……下一篇文章里要引用一下……所以……也为了方便日后查询……嘿嘿……
    --------------------------------------------------------
    原来是为复杂的东西做基础啊

  9. 老赵
    admin
    链接

    老赵 2009-05-25 09:06:00

    @技术爱好者
    其实也不复杂

  10. xuefly
    *.*.*.*
    链接

    xuefly 2009-05-25 09:12:00

    --引用--------------------------------------------------
    技术爱好者: --引用--------------------------------------------------
    Jeffrey Zhao: @Anders Cui
    因为……其实是……那个……下一篇文章里要引用一下……所以……也为了方便日后查询……嘿嘿……
    --------------------------------------------------------
    原来是为复杂的东西做基础啊
    --------------------------------------------------------
    谁能猜出来老赵下一篇写什么?
    大家猜猜

  11. 老赵
    admin
    链接

    老赵 2009-05-25 09:27:00

    @xuefly
    我现在只希望让新版式赶快出来,我写的时候可以用丰富一点的样式。

  12. James.Ying
    *.*.*.*
    链接

    James.Ying 2009-05-25 09:28:00

    --引用--------------------------------------------------
    xuefly: --引用--------------------------------------------------
    技术爱好者: --引用--------------------------------------------------
    Jeffrey Zhao: @Anders Cui
    因为……其实是……那个……下一篇文章里要引用一下……所以……也为了方便日后查询……嘿嘿……
    --------------------------------------------------------
    原来是为复杂的东西做基础啊
    --------------------------------------------------------
    谁能猜出来老赵下一篇写什么?
    大家猜猜
    --------------------------------------------------------
    该出来模板了吧,等着呢

  13. kiler
    *.*.*.*
    链接

    kiler 2009-05-25 10:33:00

  14. 老赵
    admin
    链接

    老赵 2009-05-25 10:40:00

    @kiler
    谢谢,有机会我都会尝试一下的。

  15. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-05-25 14:48:00

    我来做个 linq 练习


    const string[] spliter = { "/", ":" };
    static System.Collections.Specialized.NameValueCollection ParseArguments(string[] args)
    {

    var arguments = new System.Collections.Specialized.NameValueCollection();
    (args.Select(o => o.Split(spliter, StringSplitOptions.RemoveEmptyEntries))).ToList().ForEach(o => arguments.Add(o[0], o[1]));
    return arguments;
    }

  16. 老赵
    admin
    链接

    老赵 2009-05-25 15:04:00

    @韦恩卑鄙
    ForEach没有加在IEnumerable<T>上真是件恶心的事情。

  17. 小弟我低调
    *.*.*.*
    链接

    小弟我低调 2009-05-25 16:00:00

    你太强了,以后请多赐教哦.

  18. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-05-25 17:08:00

    --引用--------------------------------------------------
    Jeffrey Zhao: @韦恩卑鄙
    ForEach没有加在IEnumerable&lt;T&gt;上真是件恶心的事情。
    --------------------------------------------------------
    可能是为了要确定 foreach的成员 是已经执行过的结果?

  19. 老赵
    admin
    链接

    老赵 2009-05-25 17:17:00

    @韦恩卑鄙
    为什么要确定这个呢?
    如果没有在IEnumerable上提供ForEach,用户直接用foreach的话,也就是:
    foreach (var item in ...) // 某延迟计算的IEnumerator
    还是不确定foreach的成员已经全部执行完毕了。
    所以其实,平时的做法也是不保证的,如果要保证,让用户自己ToList一下也可以嘛。

  20. 陈 亮
    *.*.*.*
    链接

    陈 亮 2009-05-26 13:38:00

    我也觉得 IEnumerable 没有Foreach 蛮恶心的 .
    还有 我经常使用 ToList<T>().Foreach 这样和直接foreach 效率是不是差不多的.?

  21. 老赵
    admin
    链接

    老赵 2009-05-26 14:33:00

    @陈 亮
    为什么不自己补充一个ForEach呢,呵呵,几行代码。
    性能差距其实就是构造一个List,效率差多少视情况而定。

  22. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-05-26 15:04:00

    对哦 最近给我一个接口加了一个扩展方法
    咱也可以给IEnumerable加

    NND 这样下去不就可以多继承了么


    话说老赵 我感觉 MVC有点入门了
    开始重读你的帖了

  23. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-05-26 15:10:00

    --引用--------------------------------------------------
    Jeffrey Zhao: @韦恩卑鄙
    为什么要确定这个呢?
    如果没有在IEnumerable上提供ForEach,用户直接用foreach的话,也就是:
    foreach (var item in ...) // 某延迟计算的IEnumerator
    还是不确定foreach的成员已经全部执行完毕了。
    所以其实,平时的做法也是不保证的,如果要保证,让用户自己ToList一下也可以嘛。
    --------------------------------------------------------
    我发现偶尔的状况下 l2q 和EF的一个query(也是IEnumerable《T》) 被foreach以后就不能再次 foreach了

    是不是因为这个呢?不能反复用的就干脆取消?

  24. 老赵
    admin
    链接

    老赵 2009-05-26 15:16:00

    @韦恩卑鄙
    被foreach后就不能再foreach了,不知道……
    不是多继承,是多修饰,有点mixin的意思。

  25. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-05-26 15:26:00

    恩, 多修饰 这个词好

  26. JimLiu
    *.*.*.*
    链接

    JimLiu 2009-06-02 12:37:00

    我觉得.NET FCL对命令行输入的功能真是弱啊(可能是我对类库了解不够哈)
    C++中用cin实在太方面了,而且自己做重载操作符可以实现相当优雅(起码是华丽)。Java中的System.in提供的方法也对处理命令行输入很方便。
    而Console.Read()和Console.ReadLine()在处理输入格式化数据的时候,说实话……有点尴尬
    毕竟你读一系列连续整数,while (cin >> a)这是多么惬意的事情。
    不知道有没有相关的类库啊……我非常需要。
    不过输出够用了,String.Format真是好东西。

    其实我指的是标准输入流……- -尴尬了……

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我