Repository navigation
Binding
This library uses reflection to get a list of available verbs. Each method with a suitable signature can be called via the command line. Requirements for method are:
- Have return type of
intorTask<int> - Be non-generic method
- Be non-special method (not a property getter, operator etc.)
Before version 2.2.1, generic methods, property getters and operators returning int were also discovered as verbs. Mark them with [NonVerb] on older versions.
- Have no
NonVerbAttributeattribute on it
Both static and instance methods are verbs, whatever their visibility: private and internal methods are discovered too. Mark helper methods returning int with [NonVerb] to exclude them:
[NonVerb]
private static int ParseLevel(string text) { /* ... */ }For an instance method, the class is resolved from the configured IServiceProvider or, if it is not registered, created with its parameterless constructor.
By default, name matching is case-insensitive. The verb name is the method name, use NameAttribute to change it:
[Name("say-hi")]
public static int Hello(string name) { /* ... */ }myapp say-hi --name Jake
#>Hello Jake!For each command line invocation, the best matching method is selected so that method overloads are supported.
Verbs could be collected from several classes by calling Use() more than once:
CommandLine
.CreateFromArguments(arguments)
.Use<FileVerbs>()
.Use<NetworkVerbs>() // verbs from both classes are available
.Run();Besides Use<T>(), there are Use(Type) and Use(Func<IVerbSetBuilder>). The last one lets you build a VerbSet yourself, for example from a list of Verb objects.
Options are bound to the corresponding method parameters by name.
int Hello(string name)
{
Console.WriteLine("Hello " + name + "!");
return 0;
}myapp HELLO --name Jake
#>Hello Jake!By default, name matching is case-insensitive:
myapp hello --NAME Jake
#>Hello Jake!Option name is the parameter name. Use NameAttribute on a parameter to change it and AliasAttribute to add a short name:
int Hello([Name("who"), Alias("w")] string name) { /* ... */ }myapp HELLO --who Jake
myapp HELLO -w JakeRequired options could be bound by position:
myapp HELLO Jake
#>Hello Jake!To be more detailed, values for positional binding are taken from the values and, accordingly, "steal" the elements from this list.
You can add array/list options to collect multiple values as shown below:
int Hello(string[] names)
{
Console.WriteLine("Hello " + string.Join(", ", names) + "!");
return 0;
}myapp HELLO --names Mike Jake
#>Hello Mike, Jake!Options accepting multiple values can be only named. Such options capture all values after until another option or the end of options -- is encountered.
By default option require value and cause error if none provided. You can make any option non required by specifying default value:
int Print(int myOptionalParam = 100)
{
Console.WriteLine("myOptionalParam=" + myOptionalParam);
return 0;
}myapp PRINT --myOptionalParam 200
#>myOptionalParam=200
myapp PRINT
#>myOptionalParam=100Non required options cannot be bound by position:
myapp PRINT 200
#>myOptionalParam=100Option could be declared as "flag" if it has bool type in declaration:
int Flag(bool myFlag)
{
Console.WriteLine(myFlag ? "Flag is set" : "Flag is not set");
return 0;
}myapp.exe FLAG --myFlag
#>Flag is set
myapp.exe FLAG --myFlag true
#>Flag is set
myapp.exe FLAG
#>Flag is not set
myapp.exe FLAG --myFlag false
#>Flag is not set
myapp.exe FLAG false
#>Flag is not setYou can get the number of times this flag has been set in command line with following code:
int Flag([Alias("v")] OptionCount verbosityLevel)
{
Console.WriteLine("Verbosity level: " + verbosityLevel);
return 0;
}This also works with short aliases:
myapp.exe FLAG -vvvv
#>Verbosity level: 4Any values not captured by options and not stolen by a positional binding end up in the collection of values and can be retrieved with params parameter.
int MyMethod(params string[] values)
{
Console.WriteLine("Values are: " + string.Join(", ", values));
return 0;
}myapp.exe MYMETHOD First Second Third
#>Values are: First, Second, ThirdIf you require services from your IServiceProvider within an verb method, then you have two options:
- Declare a parameter with the required type of service and apply
[FromService]attribute to it.
int AddAccount([FromService] IAccountService accountService, string name /* ... */)
{
// ...
}- Or use the constructor of the verb's class to pass services that will be resolved from the configured
IServiceProvider.
class AccountsApi
{
private readonly IAccountService accountService;
public AccountsApi(IAccountService accountService) // your IServiceProvider should support constructor parameter injection
{
this.accountService = accountService;
}
int AddAccount(string name /* ... */)
{
// ...
}
}While running CommandLine monitors the attempt to stop or interrupt the application and provides access to this event through CancellationToken. You can inject this token via a parameter:
Task<int> LongTask(CancellationToken cancellation)
{
// ...
}The token is cancelled when:
- the token passed to
RunAsync(cancellationToken)is cancelled (in .NET Generic Host, when the host stops); -
Ctrl+Cis pressed andCommandLineConfiguration.HookConsoleCancelKeyPressistrue; - the
InterruptTokenof a customIConsoleis cancelled.
You can access the execution context of the verb by declaring a special parameter:
int MyAwareTask(VerbExecutionContext context)
{
// context.VerbSetBuilder
// context.Verb
// context.Arguments
// context.ServiceProvider
// context.Configuration
// context.Properties
}The following types are automatically bound and do not require additional configuration:
- Primitive types (int, byte, char ...)
- BCL types (String, DateTime, Decimal)
- Nullable types
- Enum types, including flags. Names are matched case-insensitively (
--color greenbindsColor.Green) - Types with TypeConverterAttribute (Point, Guid, Version, TimeSpan ...)
- Types with Parse(string value) method (IpAddress, Guid ...)
- Types with explicit/implicit conversion from string
If you need to provide custom type conversion, then specify your ITypeConversionProvider service when configuring CommandLine. See Extensibility.