-
Notifications
You must be signed in to change notification settings - Fork 395
How to use IConsole, global options, and complex parameter types with SetHandler? #1988
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
There are SetHandler overloads for handlers receving an InvocationContext: Handler.SetHandler(this Command command, Action<InvocationContext> handle)
Handler.SetHandler(this Command command, Func<InvocationContext, Task> handle) The ParseResult as well as the IConsole are provided by the InvocationContext. As you might notice, you can't put both options/arguments and InvocationContext together as handler parameters (which also has received comments in the past).
If you want complex option model types, it's probably better to use the System.CommandLine.NamingConventionBinder package, as the page with the examples you linked to mentions at the very beginning. Note however that this package, due to it relying on reflection, will not provide (easy) support for trimming and/or native AOT compiling, if that is of interest to you... (P.S.: Be careful about relying on old-ish comments/threads. The library is still in active and heavy development and has undergone substantial changes in the last two years or so. Basically, some explanations/comments older than one or two years might not fully apply to the current/latest System.CommandLine version(s) anymore...) |
Thanks, @elgonzo. Between your reply and some additional documentation I was reading, I have gotten past this issue, and am going to mark it as closed. A rough outline of how the CLI I am building works now: public class MyRootCommand : RootCommand
public static readonly Option<bool> DryRunGlobalOption = ...;
// other options
public MyRootCommand(string name) : base(name, "...")
{
AddGlobalOption(DryRunGlobalOption);
// ...
} Individual commands will define their own options and access them and/or the global options. Due to the sheer number of options I have, I need to utilize the public class MyCommand1 : Command
public static readonly Option<bool> SwitchOption1 = ...;
// other options
public MyCommand1(string name) : base(name, "...")
{
AddOption(SwitchOption1);
// ...
SetHandler(Foo);
}
private void Foo(InvocationContext context)
{
var globalOptions = new GlobalOptions(
context.ParseResult.GetValueForOption(MyRootCommand.DryRunGlobalOption),
...);
var switch1 = context.ParseResult.GetValueForOption(SwitchOption1);
// ... gather other options
Bar(context.Console, globalOptions, switch1, ...);
}
private void Bar(IConsole console, GlobalOptions globalOptions, bool switch1, ...)
{
// implementation
} This is more than sufficient for my purposes, without needing to delve into the |
System.CommandLine version:
2.0.0-beta4.22272.1
Looking through the repo docs, I am seeing references to
CommandHandler.Create
, which seems like it has been removed in favor of usingcommand.SetHandler
.However, the new
SetHandler
API does not seem to enable this example in the docs, where a custom, complex type is bound to a single handler parameter from two or more command options.The
SetHandler
API also does not seem to enable this example from the docs, whereIConsole
is injected automatically.The crux of the issues with these 2 examples (besides the docs still referencing
CommandHandler.Create
) is the fact that theSetHandler
api only allows for command handlers taking these types of parameter sets:0 parameters
1 InvocationContext parameter
1 parameter per Option which corresponds to a T1, T2, etc type parameter
This lead me to initially defining a handler with 1 parameter per option, but I quickly ran out of overloads which allowed this. I did find some guidance here, which indicates that this issue can be solved by creating a complex type to which allows for multiple Options to map to a single handler parameter. However, this approach will not compile.
My specific use case is one where I have a few commands which have specific options, but I also have a set of global options - such as the Verbosity option, as well as a Dry Run option. I would like to be able to access those options via a Complex Type which I would define to house all of these possible global options, such as:
This, too, does not seem possible with the
SetHandler
API, as there would be multiple Global options, but they would be bound to a single parameter for my handler:I also attempted to go a step further, and define a class which would be used for all of my sub commands arguments, but this runs into the same issue of signature mismatch:
Also, I'm not certain this would even work, as based on this comment, this may fall into the 'recursive' category.
TLDR:
parseResult
and/orIConsole
in a command handler usingSetHandler
?SetHandler
API?The text was updated successfully, but these errors were encountered: