c# - ¿Cómo hacer valer las opciones de línea de comando requeridas con NDesk.Options?
console-application command-line-parsing (2)
El problema es que la documentación no es tan clara como aparentemente debe ser. :-(
Específicamente, según:
El =
dentro de una especificación de opción no se aplica al conjunto de opciones como un todo, sino solo al valor para esa opción específica.
La importancia de esto solo es relevante en dos escenarios, así que primero consideremos el analizador OptionSet:
string a = null;
string b = null;
var options = new OptionSet {
{ "a=", v => a = v },
{ "b=", v => b = v },
};
El escenario 1 en el que es importante es que OptionSet.Parse () funciona de una sola pasada, solo de reenvío, y no mira los valores de las opciones para determinar si "deberían ser" valores. Por lo tanto, considere:
options.Parse(new[]{"-a", "-b"});
El resultado de esto será que a
tiene el valor "-b"
b
es null
. Como el controlador para -a
requiere un valor, siempre obtiene el siguiente valor (a menos que el valor esté "codificado" en la opción original, por ejemplo, -a=value
).
El segundo lugar donde esto es importante es cuando una opción que requiere valor es la última opción, y no hay un valor presente para ella:
options.Parse(new[]{"-a"});
Esto lanzará una OptionException, ya que el controlador para -a
requiere un valor y no hay ningún valor presente.
En consecuencia, si tiene una opción que se requiere (a diferencia de una opción que requiere un valor), debe verificar manualmente esto:
string dir = null;
new OptionSet {
{ "o=", v => dir = v },
}.Parse (args);
if (dir == null)
throw new InvalidOperationException ("Missing required option -o=DIR");
Estaba escribiendo una utilidad de consola y decidí usar NDesk.Options para el análisis de línea de comandos. Mi pregunta es, ¿cómo hago cumplir las opciones de línea de comando requeridas?
Veo en los docs que:
opciones con un valor requerido (añada ''='' al nombre de la opción) o un valor opcional (añada '':'' al nombre de la opción).
Sin embargo, cuando pongo a =
al final del nombre de la opción, no hay diferencia en el comportamiento. Idealmente, el método Parse arrojaría una excepción.
¿Hay algo más que deba hacer?
Aquí está mi código de prueba:
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);
}
}
Uno puede extender NDesk.Options un poco para agregar esta funcionalidad.
Primero, cree una clase SetupOption que implementaría 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"));
}
}
}
}
En segundo lugar, agregue una sobrecarga a ActionOption que toma una instancia de INotifyPropertyChanged como un argumento (llámelo targetValue).
En tercer lugar, modifique la clase Opción para agregar INotifyPropertyChanged targetValue privado y private bool optionSet.
En cuarto lugar, pase el targetValue a la opción al crearlo. Suscríbase al evento PropertyChanged. En él, establece "optionSet" en true si el emisor no es nulo.
Agregue un método Validate () a la clase Option que lanzaría una excepción si targetValue no es nulo y optionSet es falso.
Finalmente, agregue un método Validate () al OptionContext que recorrería todas las opciones y llamaría a sus respectivos métodos Validate (). Llámalo al final del método Parse ().
Aquí está el zip del código modificado: http://www.davidair.com/misc/options.zip