command-line-api icon indicating copy to clipboard operation
command-line-api copied to clipboard

Custom binder with static types

Open qui8t opened this issue 2 years ago • 5 comments

According to these docs, you may implement a custom binder as the following:

public class Person
{ 
    public string? Name {set; get;} 
}

public class PersonBinder : BinderBase<Person>
{
    private readonly Option<string> _nameOption;

    public PersonBinder(Option<string> nameOption)
    { _nameOption = nameOption; }

    protected override Person GetBoundValue(BindingContext context) =>
        new Person { Name = context.ParseResult.GetValueForOption(_nameOption) };
}

static async Task Main(string[] args)
{
    var nameOption = new Option<string>("--name");
    var rootCommand = new RootCommand();
    rootCommand.Add(nameOption);
    rootCommand.SetHandler((person) =>
    { DoRootCommand(person); },
    new PersonBinder(nameOption));
    await rootCommand.InvokeAsync(args);
}

public static void DoRootCommand(Person person)
{ Console.WriteLine($"Person = {person?.Name}"); }

I wonder how would you modify the PersonBinder to work with static class Person?

qui8t avatar Sep 15 '22 12:09 qui8t

Would the following setup be the only currently supported workaround?

public static class Person
{ 
    public static string? Name {set; get;} 
}

public class PersonBinder : BinderBase<bool>
{
    private readonly Option<string> _nameOption;

    public PersonBinder(Option<string> nameOption)
    { _nameOption = nameOption; }

    protected override bool GetBoundValue(BindingContext context)
    {
        Person.Name = context.ParseResult.GetValueForOption(_nameOption);
        return true;
    }
}

Using bool as a lightweight object that mainly serves the purpose of an enabler for using static Person.

qui8t avatar Sep 16 '22 02:09 qui8t

I feel it would be clearer to pass the string to DoRootCommand and assign to Person.Name there. Easier for future maintainers to understand than a binder with side effects.

KalleOlaviNiemitalo avatar Sep 16 '22 05:09 KalleOlaviNiemitalo

That is a possibility; though in my use case, the Person (its equivalent of course) has a decent number of attributes that are set through different commands of the CLI, which makes the binding the only clean approach.

qui8t avatar Sep 16 '22 12:09 qui8t

Custom middleware could look up the values of the options from InvocationContext.ParseResult and assign the static properties.

KalleOlaviNiemitalo avatar Sep 16 '22 15:09 KalleOlaviNiemitalo

Could you please provide an example?

qui8t avatar Sep 16 '22 22:09 qui8t