How to enforce required command-line options with NDesk.Options?

前端 未结 2 1359
青春惊慌失措
青春惊慌失措 2020-12-09 01:33

I was just writing a console utility and decided to use NDesk.Options for command-line parsing. My question is, How do I enforce required command-line options?

I se

相关标签:
2条回答
  • 2020-12-09 02:10

    One can extend NDesk.Options a little bit to add this functionality.

    First, create a SetupOption class that would implement INotifyPropertyChanged:

    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"));
                }
            }
        }
    }
    

    Second, add an overload to ActionOption that takes an instance of INotifyPropertyChanged as an argument (call it targetValue).

    Third, modify the Option class to add private INotifyPropertyChanged targetValue and private bool optionSet.

    Fourth, pass the targetValue to the Option when creating it. Subscribe to the PropertyChanged event. In it, set "optionSet" to true if the sender is not null.

    Add a Validate() method to the Option class that would throw an exception if targetValue is not null and optionSet is false.

    Finally, add a Validate() method to the OptionContext that would loop over all options and call their respective Validate() methods. Call it at the very end of the Parse() method.

    Here is the zip of the modified code: http://www.davidair.com/misc/options.zip

    0 讨论(0)
  • 2020-12-09 02:11

    The problem is that documentation isn't as clear as it apparently needs to be. :-(

    Specifically, as per:

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

    The = within an option specification doesn't apply to the OptionSet as a whole, but just to the value for that specific option.

    The importance of this is really only relevant in two scenarios, so first let's consider the OptionSet parser:

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

    Scenario 1 where it's important is that OptionSet.Parse() works in a single-pass, forward-only manner, and does not look at option values to determine if they "should be" values. Thus, consider:

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

    The result of this will be that a has the value "-b", and b is null. Since the handler for -a requires a value, it always gets the following value (unless the value is "encoded" into the original option, e.g. -a=value).

    The second place where this is important is when a value-requiring option is the last option, and there isn't a value present for it:

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

    This will throw an OptionException, as the handler for -a requires a value, and no value is present.

    Consequently, if you have an option that itself is required (as opposed to an option that requires a value), you need to manually check for this:

    string dir = null;
    new OptionSet {
        { "o=", v => dir = v },
    }.Parse (args);
    
    if (dir == null)
        throw new InvalidOperationException ("Missing required option -o=DIR");
    
    0 讨论(0)
提交回复
热议问题