【问题标题】:How to enforce required command-line options with NDesk.Options?如何使用 NDesk.Options 强制执行所需的命令行选项?
【发布时间】:2011-03-26 12:47:48
【问题描述】:

我只是在编写一个控制台实用程序,并决定使用 NDesk.Options 进行命令行解析。我的问题是,如何强制执行所需的命令行选项?

我在docs 中看到:

具有必需值(将“=”附加到选项名称)或可选值(将“:”附加到选项名称)的选项。

但是,当我将= 放在选项名称的末尾时,行为没有区别。理想情况下,Parse 方法会抛出异常。

我还有什么需要做的吗?

这是我的测试代码:

class Program
{
    static void Main(string[] args)
    {
        bool show_help = false;
        string someoption = null;

        var p = new OptionSet() {
            { "someoption=", "Some String Option", v => someoption = v},
            { "h|help",  "show this message and exit", v => show_help = v != null }
        };

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

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

        System.Console.WriteLine("==================");
        System.Console.WriteLine(someoption);
    }

    static void ShowHelp(OptionSet p)
    {
        System.Console.WriteLine("Usage: myconsole [OPTIONS]");
        System.Console.WriteLine();
        System.Console.WriteLine("Options:");
        p.WriteOptionDescriptions(System.Console.Out);
    }
}

【问题讨论】:

  • 我也有同样的问题。 Seams NDesk.Options 不会抛出异常。

标签: c# console-application command-line-arguments ndesk.options


【解决方案1】:

问题在于文档并不像它显然需要的那样清晰。 :-(

具体如下:

http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionValueType.html#F:NDesk.Options.OptionValueType.Required

选项规范中的= 不适用于整个OptionSet,而仅适用于该特定选项的

这一点的重要性实际上只在两种情况下相关,所以首先让我们考虑一下 OptionSet 解析器:

string a = null;
string b = null;
var options = new OptionSet {
    { "a=", v => a = v },
    { "b=", v => b = v },
};

场景 1 重要的是 OptionSet.Parse() 以单次传递、仅向前的方式工作,并且查看选项值以确定它们是否“应该是”值.因此,考虑:

options.Parse(new[]{"-a", "-b"});

这样的结果将是a 的值是"-b",而bnull。由于-a 的处理程序需要 一个值,它总是 获取以下值(除非该值被“编码”到原始选项中,例如-a=value)。

这很重要的第二个地方是当一个需要值的选项是最后一个选项时,它没有值存在:

options.Parse(new[]{"-a"});

这将引发 OptionException,因为 -a 的处理程序需要一个值,但没有值存在。

因此,如果您有一个本身是必需的选项(而不是一个需要值的选项),您需要手动检查:

string dir = null;
new OptionSet {
    { "o=", v => dir = v },
}.Parse (args);

if (dir == null)
    throw new InvalidOperationException ("Missing required option -o=DIR");

【讨论】:

    【解决方案2】:

    可以稍微扩展 NDesk.Options 以添加此功能。

    首先,创建一个将实现 INotifyPropertyChanged 的​​ SetupOption 类:

    class SetupOption<T> : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged Members
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        #endregion
    
        private T _value;
    
        public T Value
        {
            get
            {
                return _value;
            }
            set
            {
                _value = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(_value, new PropertyChangedEventArgs("Value"));
                }
            }
        }
    }
    

    其次,向 ActionOption 添加一个重载,将 INotifyPropertyChanged 的​​实例作为参数(称为 targetValue)。

    三、修改Option类,增加private INotifyPropertyChanged targetValue和private bool optionSet。

    第四,在创建时将targetValue传递给Option。订阅 PropertyChanged 事件。在其中,如果发送者不为空,则将“optionSet”设置为true。

    向 Option 类添加一个 Validate() 方法,如果 targetValue 不为 null 且 optionSet 为 false,则会引发异常。

    最后,向 OptionContext 添加一个 Validate() 方法,该方法将遍历所有选项并调用它们各自的 Validate() 方法。在 Parse() 方法的最后调用它。

    这里是修改后代码的zip:http://www.davidair.com/misc/options.zip

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-04
      • 1970-01-01
      • 1970-01-01
      • 2016-04-09
      • 2011-06-30
      • 2011-05-01
      相关资源
      最近更新 更多