Using Flag Arguments

How to use FlagValue for optional flag arguments that may or may not include a value

Sometimes you need a flag that can be used in three ways: not present, present without a value (using a default), or present with an explicit value. The FlagValue<T> type handles this pattern cleanly.

What We're Building

The --port flag used three ways: omitted entirely, present without a value (uses default 3000), or with an explicit value like --port 8080:

Flag arguments demonstration

Define a Flag Value

Use FlagValue<T> with square brackets in the template to indicate the value is optional. When users specify --port without a value, the flag is set but uses the type's default. When they specify --port 8080, the flag is set with that value.

public class Settings : CommandSettings
{
    [CommandOption("--port [PORT]")]
    [Description("The port to listen on (default: 3000 if flag present)")]
    [DefaultValue(3000)]
    public required FlagValue<int> Port { get; init; }
  
    [CommandOption("--timeout [SECONDS]")]
    [Description("Connection timeout in seconds")]
    public required FlagValue<int?> Timeout { get; init; }
  
    [CommandOption("-h|--host")]
    [Description("The host to bind to")]
    [DefaultValue("localhost")]
    public required string Host { get; init; } = "localhost";
}

This produces the following usage:

USAGE:
    myapp [OPTIONS]
  
OPTIONS:
    --port [PORT]           The port to listen on (default: 3000 if flag present)
    --timeout [SECONDS]     Connection timeout in seconds
    -h, --host              The host to bind to [default: localhost]

Check if a Flag Was Provided

The FlagValue<T> type has two properties: IsSet indicates whether the flag was present on the command line, and Value contains the parsed value (or the type's default if no value was given).

System.Console.WriteLine($"Host: {settings.Host}");
  
// Check if --port flag was provided
if (settings.Port.IsSet)
{
    System.Console.WriteLine($"Port: {settings.Port.Value}");
}
else
{
    System.Console.WriteLine("Port: not specified (will use system default)");
}
  
// Check if --timeout flag was provided
if (settings.Timeout is { IsSet: true, Value: not null })
{
    System.Console.WriteLine($"Timeout: {settings.Timeout.Value} seconds");
}
else if (settings.Timeout.IsSet)
{
    System.Console.WriteLine($"Timeout: system default seconds");
}
else
{
    System.Console.WriteLine("Timeout: disabled");
}
  
return 0;

This lets you distinguish between:

  • myapp — flag not present (IsSet is false)
  • myapp --port — flag present without value (IsSet is true, Value is 0)
  • myapp --port 8080 — flag present with value (IsSet is true, Value is 8080)

See Also