Skip to content

Option vs Operand#

It is not always clear when to use an option vs operand. Below are a couple of strategies to help.

Every argument an option.#

Set AppSettings.DefaultArgumentMode to ArgumentMode.Option and treat every argument as an option.

Advantages

  • User cannot accidently provide arguments in the wrong order
  • Adding arguments is less likely to introduce breaking changes
  • If the console input is logged, it's easier to determine user intent at a glance. Especially for older versions of the command with different arguments

Disadvantages

  • More typing for the user. Imagine if you had to type argument names for all git commands...
    • git checkout --branch branch-name instead of git checkout branch-name
    • git push --remote origin --branch branch-name instead of git push origin branch-name

Consider how often users will be using these commands. If use will generally be from scripts and automation, use all options for backward compatibility.

Operand as "what", Option as "how"#

This approach can lead to a more elegant design of your commands.

Consider operands as "what" the command operates on and options as "how" the command operates on them, as described in this article.

In the example below, x and y are the operands and --radix informs how the numbers are represented in the operations.

public void Add(int x, int y, [Option] int? radix)
{
    Console.WriteLine(_calculator.Add(x, y, radix));
}

The exercise of distinguishing what vs how can bring clarity to your separation of concerns, leading to a cleaner interface. e.g. Identifying --radix as a "how" makes it an obvious candidate to promote to a parent command as shown in interceptors example and then it is available for other math operations.

Optional Operands#

Optional operands are a muddy topic. As a general rule, for simplicity, define them as options on the command. This is especially true if there are multiple.

This framework will assign positional arguments in the order they are specified in the shell so if a user skipped the first optional operand and provided a value for the second one, the framework would still assign the value to the first one because it cannot understand the users intent.

By defining these as options, users can specify intent with the name. This is similar to how C# uses optional parameters.