CliOptionAttribute Class

Specifies a class property that represents an option which is a named parameter and a value for that parameter, that is used on the command line.
C#
[CliOption]
public string SomeCliOption { get; set; }

Note that an option is required if the decorated property does not have a default value (set via a property initializer), see Required property for details.

Options: An option is a named parameter that can be passed to a command. The POSIX convention is to prefix the option name with two hyphens (--). The following example shows two options:

console
dotnet tool update dotnet-suggest --verbosity quiet --global
                                  ^---------^       ^------^
As this example illustrates, the value of the option may be explicit (quiet for --verbosity) or implicit (nothing follows --global). Options that have no value specified are typically Boolean parameters that default to true if the option is specified on the command line.

For some Windows command-line apps, you identify an option by using a leading slash (/) with the option name. For example:

console
msbuild /version
        ^------^
Both POSIX and Windows prefix conventions are supported. When manually setting a name (overriding decorated property's name), you should specify the option name including the prefix (e.g. `--option`, `-o`, `-option` or `/option`).

Bundling of single-character options are supported, also known as stacking. Bundled options are single-character option aliases specified together after a single hyphen prefix. For example if you have options "-a", "-b" and "-c", you can bundle them like "-abc". Only the last option can specify an argument. Note that if you have an explicit option named "-abc" then it will win over bundled options.

Definition

Namespace: DotMake.CommandLine
Assembly: DotMake.CommandLine (in DotMake.CommandLine.dll) Version: 1.8.8
C#
public class CliOptionAttribute : Attribute
Inheritance
Object    Attribute    CliOptionAttribute

Example

C#
//Delegate-based model
//In Program.cs, add this simple code:
Cli.Run(([CliArgument] string argument1, bool option1) =>
{
    Console.WriteLine($@"Value for {nameof(argument1)} parameter is '{argument1}'");
    Console.WriteLine($@"Value for {nameof(option1)} parameter is '{option1}'");
});

//Or:
Cli.Run(Method);

void Method([CliArgument] string argument2, bool option2)
{
    Console.WriteLine($@"Value for {nameof(argument2)} parameter is '{argument2}'");
    Console.WriteLine($@"Value for {nameof(option2)} parameter is '{option2}'");
}
C#
// Class-based model
// Create a simple class like this:

[CliCommand(Description = "A root cli command")]
public class RootCliCommand
{
    [CliOption(Description = "Description for Option1")]
    public string Option1 { get; set; } = "DefaultForOption1";

    [CliArgument(Description = "Description for Argument1")]
    public string Argument1 { get; set; }

    public void Run()
    {
        Console.WriteLine($@"Handler for '{GetType().FullName}' is run:");
        Console.WriteLine($@"Value for {nameof(Option1)} property is '{Option1}'");
        Console.WriteLine($@"Value for {nameof(Argument1)} property is '{Argument1}'");
        Console.WriteLine();
    }
}

        //In Program.cs, add this single line:
        Cli.Run<RootCliCommand>(args);

        //If you need to simply parse the command-line arguments without invocation, use this:
        var parseResult = Cli.Parse<RootCliCommand>(args);
        var rootCliCommand = parseResult.Bind<RootCliCommand>();
C#
// Getting the value for a recursive option in a sub-command:

[CliCommand(Description = "A root cli command")]
public class RecursiveOptionCliCommand
{
    [CliOption(Recursive = true)]
    public bool RecursiveOption { get; set; }

    [CliCommand]
    public class SubCliCommand
    {
        [CliArgument]
        public string Argument1 { get; set; } = "DefaultForArgument1";

        public async Task RunAsync(CliContext context)
        {
            var parent = context.ParseResult.Bind<RecursiveOptionCliCommand>();

            await Console.Out.WriteLineAsync($"RecursiveOption = {parent.RecursiveOption}, Argument1 = {Argument1}");
        }
    }
}
C#
// Sub-commands can get a reference to the parent command by adding a property of the parent command type.

[CliCommand(Description = "A root cli command with children that can access parent commands")]
public class ParentCommandAccessorCliCommand
{
    [CliOption(
        Description = "This is a global option (Recursive option on the root command), it can appear anywhere on the command line",
        Recursive = true)]
    public string GlobalOption1 { get; set; } = "DefaultForGlobalOption1";

    [CliArgument(Description = "Description for RootArgument1")]
    public string RootArgument1 { get; set; }

    public void Run(CliContext context)
    {
        context.ShowValues();
    }

    [CliCommand(Description = "A nested level 1 sub-command which accesses the root command")]
    public class Level1SubCliCommand
    {
        [CliOption(
            Description = "This is global for all sub commands (it can appear anywhere after the level-1 verb)",
            Recursive = true)]
        public string Level1RecursiveOption1 { get; set; } = "DefaultForLevel1RecusiveOption1";

        [CliArgument(Description = "Description for Argument1")]
        public string Argument1 { get; set; }

        // The parent command gets automatically injected
        public ParentCommandAccessorCliCommand RootCommand { get; set; }

        public void Run(CliContext context)
        {
            context.ShowValues();
        }

        [CliCommand(Description = "A nested level 2 sub-command which accesses its parent commands")]
        public class Level2SubCliCommand
        {
            [CliOption(Description = "Description for Option1")]
            public string Option1 { get; set; } = "DefaultForOption1";

            [CliArgument(Description = "Description for Argument1")]
            public string Argument1 { get; set; }

            // All ancestor commands gets injected
            public ParentCommandAccessorCliCommand RootCommand { get; set; }
            public Level1SubCliCommand ParentCommand { get; set; }

            public void Run(CliContext context)
            {
                context.ShowValues();

                Console.WriteLine();
                Console.WriteLine(@$"Level1RecursiveOption1 = {ParentCommand.Level1RecursiveOption1}");
                Console.WriteLine(@$"parent Argument1 = {ParentCommand.Argument1}");
                Console.WriteLine(@$"GlobalOption1 = {RootCommand.GlobalOption1}");
                Console.WriteLine(@$"RootArgument1 = {RootCommand.RootArgument1}");
            }
        }
    }
}
C#
// Bundling of single-character options are supported, also known as stacking.
// Bundled options are single-character option aliases specified together after a single hyphen prefix.
// For example if you have options "-a", "-b" and "-c", you can bundle them like "-abc".
// Only the last option can specify an argument.
// Note that if you have an explicit option named "-abc" then it will win over bundled options.

[CliCommand]
public class OptionBundlingCliCommand
{
    [CliOption(Name = "-a")]
    public bool A { get; set; }

    [CliOption(Name = "-b")]
    public bool B { get; set; }

    [CliOption(Name = "-c")]
    public bool C { get; set; }

    public void Run(CliContext cliContext)
    {
        cliContext.ShowValues();
    }
}

Constructors

CliOptionAttributeInitializes a new instance of the CliOptionAttribute class

Properties

Aliases Gets or sets the set of alternative strings that can be used on the command line to specify the option.

The aliases will be also displayed in usage help of the command line application.

When manually setting an alias, you should specify the option name including the prefix (e.g. --option, -option or /option)

AllowedValues Gets or sets the list of allowed values for an option.

Configures an option to accept only the specified values, and to suggest them as command line completions.

Note that if the option's argument type is an enum, values are automatically added.

AllowMultipleArgumentsPerToken Gets or sets a value that indicates whether multiple argument tokens are allowed for each option identifier token.

If set to , the following command line is valid for passing multiple arguments:

console
> myapp --opt 1 2 3
The following is equivalent and is always valid:
console
> myapp --opt 1 --opt 2 --opt 3

Arity Gets or sets the arity of the option's argument. The arity refers to the number of values that can be passed on the command line.

In most cases setting argument arity is not necessary as it is automatically determined based on the argument type (the decorated property's type):

  • Boolean -> ArgumentArity.ZeroOrOne
  • Collection types -> ArgumentArity.ZeroOrMore
  • Everything else -> ArgumentArity.ExactlyOne
Description Gets or sets the description of the option. This will be displayed in usage help of the command line application.
HelpName Gets or sets the name of the option's argument when displayed in help.
Hidden Gets or sets a value indicating whether the option is hidden.

You might want to support a command, option, or argument, but avoid making it easy to discover. For example, it might be a deprecated or administrative or preview feature. Use the Hidden property to prevent users from discovering such features by using tab completion or help.

Name Gets or sets the name of the option that will be used on the command line to specify the option. When manually setting a name (overriding target property’s name), you should specify the option name including the prefix (e.g. --option, -option or /option) This will be displayed in usage help of the command line application.

If not set (or is empty/whitespace), the name of the property that this attribute is applied to, will be used to generate option name automatically: These suffixes will be stripped from the property name: RootCliCommandOption, RootCommandOption, SubCliCommandOption, SubCommandOption, CliCommandOption, CommandOption, CliOption, Option. Then the name will be converted to kebab-case and will be prefixed with POSIX convention two hyphens (--), for example:

  • If property name is Input or InputOption or InputCliOption -> option name will be --input
  • If property name is SearchPath or SearchPathOption or SearchPathCliOption -> option name will be --search-path

Default conventions can be changed via parent command's NameCasingConvention and NamePrefixConvention properties.

Recursive Gets or sets a value indicating whether the option is added to its immediate parent command or commands and recursively to their subcommands.

For example, --help is a recursive option.

Required Gets or sets a value indicating whether the option is required when its parent command is invoked. Default is auto-detected.

An option/argument will be considered required when

  • There is no property initializer and the property type is a reference type (e.g. public string Arg { get; set; }). string is a reference type which has a null as the default value but bool and enum are value types which already have non-null default values. Nullable<T> is a reference type, e.g. bool?.
  • There is a property initializer, but it's initialized with null or null! (SuppressNullableWarningExpression) (e.g. public string Arg { get; set; } = null!;).
  • If it's forced via attribute property Required (e.g. [CliArgument(Required = true)]).
  • If it's forced via required modifier (e.g. public required string Opt { get; set; }). Note that for being able to use required modifier, if your target framework is below net7.0, you also need 11.0 tag (minimum) in your .csproj file (our source generator supplies the polyfills automatically as long as you set C# language version to 11).

An option/argument will be considered optional when

  • There is no property initializer (e.g. public bool Opt { get; set; }) but the property type is a value type which already have non-null default value.
  • There is a property initializer, and it's not initialized with null or null! (SuppressNullableWarningExpression) (e.g. public string Arg { get; set; } = "Default";).
  • If it's forced via attribute property Required (e.g. [CliArgument(Required = false)]).

When an option is required, the option has to be specified on the command line and if its parent command is invoked without it, an error message is displayed and the command handler isn't called. When an option is not required, the option doesn't have to be specified on the command line, the default value provides the option value.

ValidationMessageGets or sets an error message to show when ValidationPattern does not match and validation fails.
ValidationPattern Gets or sets a regular expression pattern used to determine if option's argument value(s) is valid.

Note that you can specify regular expression options inline in the pattern with the syntax (?imnsx-imnsx):

C#
ValidationPattern = @"(?i)^[a-z]+$"
Regular expression quick reference
Regular expression options

ValidationRules Gets or sets a set of validation rules used to determine if option's argument value(s) is valid.

When combining validation rules, use bitwise 'or' operator(| in C#):

C#
ValidationRules = CliValidationRules.NonExistingFile | CliValidationRules.LegalPath

See Also