2010-08-06 12 views
34

Stavo solo scrivendo un'utilità della console e ho deciso di utilizzare NDesk.Options per l'analisi della riga di comando. La mia domanda è, come faccio ad imporre le opzioni da riga di comando richieste?Come applicare le opzioni della riga di comando richieste con NDesk.Options?

vedo nel docs che:

opzioni con un valore desiderato (aggiungono '=' al nome dell'opzione) o un valore opzionale (aggiungere ':' al nome dell'opzione).

Tuttavia, quando inserisco uno = alla fine del nome dell'opzione non c'è differenza di comportamento. Idealmente, il metodo Parse genererebbe un'eccezione.

C'è qualcos'altro che devo fare?

Ecco il mio codice di prova:

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); 
    } 
} 
+1

Ho lo stesso problema. Le giunzioni NDesk.Options non generano eccezioni. –

risposta

39

Il problema è che la documentazione non è chiaro come a quanto pare deve essere. :-(

In particolare, secondo:

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

Il = entro una specifica opzione non si applica alla OPTIONSET nel suo complesso, ma solo per il valoreper quella specifica opzione.

l'importanza di questo è davvero rilevante solo in due scenari, quindi prima prendiamo in considerazione il parser OPTIONSET:

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

Lo scenario 1 in cui è importante è che OptionSet.Parse() funzioni in modalità passaggio singolo, solo inoltro e fa non esaminare i valori di opzione per determinare se "dovrebbero essere" i valori. Così, prendere in considerazione:

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

Il risultato di tutto ciò sarà che a ha il valore "-b", e b è null. Poiché il gestore per -arichiede un valore, il valore sempre ottiene il seguente valore (a meno che il valore non sia "codificato" nell'opzione originale, ad esempio -a=value).

Il secondo posto in cui questo è importante è quando una soluzione vantaggiosa che richiede è l'ultima opzione, e non v'è un valore attuale per esso:

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

Questo genera un OptionException, come gestore per -arichiede un valore e nessun valore è presente.

Di conseguenza, se si dispone di un'opzione che si è richiesto (al contrario di un'opzione che richiede un valore), è necessario controllare manualmente questo:

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

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

Si può estendere NDesk.Options un po ' bit per aggiungere questa funzionalità.

In primo luogo, creare una classe SetupOption che implementare 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")); 
      } 
     } 
    } 
} 

In secondo luogo, aggiungere un sovraccarico di ActionOption che prende un'istanza di INotifyPropertyChanged come argomento (lo chiamano targetvalue).

In terzo luogo, modificare la classe Option per aggiungere private INotifyPropertyChanged targetValue e private bool option Set.

In quarto luogo, passare il valore target all'opzione durante la sua creazione. Iscriviti all'evento PropertyChanged. In esso, impostare "optionSet" su true se il mittente non è nullo.

Aggiungere un metodo Validate() alla classe Option che genererebbe un'eccezione se targetValue non è null e optionSet è false.

Infine, aggiungere un metodo Validate() a OptionContext che esegue il loop su tutte le opzioni e chiama i rispettivi metodi Validate(). Chiamalo alla fine del metodo Parse().

Ecco la zip del codice modificato: http://www.davidair.com/misc/options.zip

Problemi correlati