web-dev-qa-db-ja.com

NDesk.Optionsを使用して必要なコマンドラインオプションを適用するにはどうすればよいですか?

コンソールユーティリティを書いていたところ、コマンドライン解析に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);
    }
}
34
BigJoe714

問題は、ドキュメントが明らかに必要なほど明確ではないことです。 :

具体的には、次のとおりです。

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

オプション仕様内の=は、OptionSet全体には適用されませんが、その特定のオプションのvalueにのみ適用されます。

これの重要性は、実際には2つのシナリオにのみ関連するため、最初にOptionSetパーサーについて考えてみましょう。

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

重要なシナリオ1は、OptionSet.Parse()がシングルパスの順方向のみの方法で機能し、オプション値をnotで調べないことです。それらが「あるべき」値であるかどうかを判断します。したがって、次のことを考慮してください。

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

この結果、aの値は"-b"になり、bの値はnullになります。 -aのハンドラーは値を必要とするため、常に次の値を取得します(値が元のオプションに「エンコード」されていない場合、たとえば-a=value)。

これが重要な2番目の場所は、値を必要とするオプションが最後のオプションであり、そのオプションに値が存在しない場合です。

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

-aのハンドラーは値を必要とし、値が存在しないため、これによりOptionExceptionがスローされます。

したがって、(値を必要とするオプションではなく)それ自体が必要なオプションがある場合は、これを手動で確認する必要があります。

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

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

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

次に、INotifyPropertyChangedのインスタンスを引数として受け取るオーバーロードをActionOptionに追加します(targetValueと呼びます)。

3番目に、Optionクラスを変更して、private INotifyPropertyChangedtargetValueとprivatebooloptionSetを追加します。

第4に、targetValueを作成するときにOptionに渡します。 PropertyChangedイベントをサブスクライブします。その中で、送信者がnullでない場合は、「optionSet」をtrueに設定します。

TargetValueがnullでなく、optionSetがfalseの場合に例外をスローするValidate()メソッドをOptionクラスに追加します。

最後に、すべてのオプションをループしてそれぞれのValidate()メソッドを呼び出すValidate()メソッドをOptionContextに追加します。 Parse()メソッドの最後で呼び出します。

変更されたコードの郵便番号は次のとおりです。 http://www.davidair.com/misc/options.Zip

2