Как применить обязательные параметры командной строки с помощью NDesk.Options? - PullRequest
34 голосов
/ 06 августа 2010

Я просто писал консольную утилиту и решил использовать NDesk.Options для анализа командной строки. У меня вопрос: как применить обязательные параметры командной строки?

Я вижу в документах , что:

опции с обязательным значением (добавьте '=' к имени опции) или необязательное значение (добавьте ':' к имени опции).

Однако, когда я ставлю = в конце имени опции, нет различий в поведении. В идеале метод 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);
    }
}

Ответы [ 2 ]

42 голосов
/ 20 сентября 2010

Проблема в том, что документация не так ясна, как это должно быть.: - (

В частности, согласно:

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", а b равно null. Поскольку для обработчика -a требуется aзначение, оно всегда получает следующее значение (если только значение не «закодировано» в исходной опции, например, -a=value).

Второе место, где это важно, это когда значениеПараметр -requiring является последним параметром, и для него нет значения:

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 голосов
/ 19 июня 2012

Можно немного расширить NDesk.Options, чтобы добавить эту функцию.

Во-первых, создайте класс SetupOption, который бы реализовывал 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"));
            }
        }
    }
}

Во-вторых, добавьте перегрузку в ActionOptionкоторый принимает экземпляр INotifyPropertyChanged в качестве аргумента (назовите его targetValue).

В-третьих, измените класс Option, добавив частный INotifyPropertyChanged targetValue и частный bool optionSet.

В-четвертых, передайте targetValueВариант при его создании.Подпишитесь на событие PropertyChanged.В нем задайте для «optionSet» значение true, если отправитель не равен нулю.

Добавьте метод Validate () в класс Option, который будет вызывать исключение, если targetValue не равен NULL и optionSet равен false.

Наконец, добавьте метод Validate () в OptionContext, который будет перебирать все параметры и вызывать их соответствующие методы Validate ().Вызовите его в самом конце метода Parse ().

Вот индекс модифицированного кода: http://www.davidair.com/misc/options.zip

...