fclp / fluent-command-line-parser

A simple, strongly typed .NET C# command line parser library using a fluent easy to use interface
Other
530 stars 86 forks source link

Feature Request: Cross object property binding for parser. #105

Open nathan130200 opened 5 years ago

nathan130200 commented 5 years ago

Since i have two classes, i need to parse CLI args to specfic classes:

public class Class1 
{
  public bool SomeCondition { get; set; }
  public string SomeText { get; set; }
}

public class Class2 
{
  public int SomeNumber { get; set; }
}

public class RootClass
{
  public Class1 C1 { get; set; } = new Class1();
  public Class2 C2 { get; set; } = new Class2();
}

My feature request is: Allow to parse CLI Arguments into RootClass and sub classes properties like:

var parser = new FluentCommandLineParser<RootClass>();
parser.Setup(x => x.C1.SomeCondition)
  .As("c1-some-condition")
  .SetDefault(true);

parser.Setup(x => x.C1.SomeText)
  .As("c1-some-text")
  .Required();

parser.Setup(x => x.C2.SomeNumber)
  .As("c2-some-number")
  .SetDefault(10);

Currently if i try to do this, causes exception.


System.Reflection.TargetException: 'Object does not match target type.'

   at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target)
   at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
   at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, Object[] index)
   at Fclp.Internals.CommandLineOption`1.Bind(ParsedOption value)
   at Fclp.FluentCommandLineParser.ParseOptions(IEnumerable`1 options, List`1 parsedOptions, CommandLineParserResult result)
   at Barberians.Program.Main(String[] args) in C:\Users\Nathan Ferreira\Desktop\Barberians\Barberians\Program.cs:line 28

Since C1 and C2 instances are not null.

In real code:

var parser = new FluentCommandLineParser<BarberiansOptions>()
    .UseOwnOptionPrefix("+")
    .MakeCaseInsensitive()
    .DisableShortOptions();

parser.Setup(x => x.Discord.Token)
    .As("ds_token")
    .Required();

var result = parser.Parse(args); // exception thrown here.
if (result.HasErrors)
{
    Console.WriteLine(result.ErrorText);
    Console.ReadKey();
}
siywilliams commented 5 years ago

I did not see that use-case coming !

I think there needs to be a bit of extra smartness around the reflection usage as the property it is trying to set the value on does not exist on the generic type FluentCommandLineParser is constructed with.