Skip to content

System.CommandLine docs update #46594

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

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open

System.CommandLine docs update #46594

wants to merge 14 commits into from

Conversation

adamsitnik
Copy link
Member

@adamsitnik adamsitnik commented Jun 6, 2025

High level overview:

  1. I've merged the doc that explains the syntax (https://learn.microsoft.com/en-us/dotnet/standard/commandline/syntax) without showing the code and the doc that shows the related code (https://learn.microsoft.com/en-us/dotnet/standard/commandline/define-commands) into one.
  2. I've moved the "Command-line design guidance" from syntax doc to a dedicated doc (it's big and important, but the very new users don't need to ready it when learning about syntax for the first time).
  3. I've introduced a dedicated doc about how to parse and invoke to show it's two separate things.
  4. I've introduced dedicated doc about other features such as parsing and validation etc
  5. I've simplified the tutorial to start with a code that does not use invoking at all, just to show all its benefits and gradually use more features.

Internal previews

Toggle expand/collapse
📄 File 🔗 Preview link
docs/fundamentals/toc.yml docs/fundamentals/toc
docs/standard/commandline/beta5.md Breaking changes in beta5
docs/standard/commandline/command-line-configuration.md How to configure the parser in System.CommandLine
docs/standard/commandline/design-guidance.md Design guidance
docs/standard/commandline/get-started-tutorial.md Tutorial: Get started with System.CommandLine
docs/standard/commandline/help.md docs/standard/commandline/help
docs/standard/commandline/index.md System.CommandLine Overview
docs/standard/commandline/parse-and-invoke.md "How to parse and invoke the result"
docs/standard/commandline/parsing-and-validation.md How to customize parsing and validation in System.CommandLine
docs/standard/commandline/syntax.md Syntax overview: commands, options, and arguments
docs/standard/commandline/tab-completion.md docs/standard/commandline/tab-completion

@adamsitnik adamsitnik requested review from tdykstra and a team as code owners June 6, 2025 19:01
@dotnetrepoman dotnetrepoman bot added this to the June 2025 milestone Jun 6, 2025
ms.topic: conceptual
---

# Design guidance
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


[!INCLUDE [scl-preview](../../../includes/scl-preview.md)]

Our main focus for beta5 was to improve the APIs and take a step toward releasing a stable version of System.CommandLine. We have simplified the APIs and made them more consistent and coherent with the [Framework design guidelines](../design-guidelines/index.md). This article describes the breaking changes that were made in beta5 and the reasoning behind them.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Our main focus for beta5 was to improve the APIs and take a step toward releasing a stable version of System.CommandLine. We have simplified the APIs and made them more consistent and coherent with the [Framework design guidelines](../design-guidelines/index.md). This article describes the breaking changes that were made in beta5 and the reasoning behind them.
Our main focus for beta5 was to improve the APIs and take a step toward releasing a stable version of System.CommandLine. We have simplified the APIs and made them more coherent and consistent with the [Framework design guidelines](../design-guidelines/index.md). This article describes the breaking changes that were made in beta5 and the reasoning behind them.


### Creating options with aliases

In the past, `Option<T>` was exposing plenty of constructors, some of which were accepting the name or not. Since the name is now mandatory and we expect aliases to be frequetly provided for `Option<T>`, we provide only a single constrtor. It accepts the name and a `params` array of aliases.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In the past, `Option<T>` was exposing plenty of constructors, some of which were accepting the name or not. Since the name is now mandatory and we expect aliases to be frequetly provided for `Option<T>`, we provide only a single constrtor. It accepts the name and a `params` array of aliases.
In the past, `Option<T>` exposed many constructors, some of which accepted the name. Since the name is now mandatory and we expect aliases to be frequently provided for `Option<T>`, we provide only a single constructor. It accepts the name and a `params` array of aliases.


Before beta5, `Option<T>` had a constructor that took a name and a description. Because of that, the second argument might now be treated as an alias rather than a description. It's the only known breaking change in the API that is not going to cause a compiler error.

Old code that used the constructor with a description should be updated to use the new constructor that takes a name and aliases, and then set the `Description` property separately. For example:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Old code that used the constructor with a description should be updated to use the new constructor that takes a name and aliases, and then set the `Description` property separately. For example:
Old code that used the constructor with a description should be updated to use the new constructor which takes a name and aliases, and then set the `Description` property separately. For example:


## Default values

In beta4, users could set default values for options and arguments by using the `SetDefaultValue` methods. Those methods were accepting an `object` value, which was not type-safe and could lead to runtime errors if the value was not compatible with the option or argument type:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In beta4, users could set default values for options and arguments by using the `SetDefaultValue` methods. Those methods were accepting an `object` value, which was not type-safe and could lead to runtime errors if the value was not compatible with the option or argument type:
In beta4, users could set default values for options and arguments by using the `SetDefaultValue` methods. Those methods accepted an `object` value, which was not type-safe and could lead to runtime errors if the value was not compatible with the option or argument type:


Moreover, some of the `Option` and `Argument` constructors accepted a parse delegate and a boolean indicating whether the delegate was a custom parser or a default value provider. This was confusing.

`Option<T>` and `Argument<T>` classes now have a `DefaultValueFactory` property that can be used to set the default value for the symbol. This property is invoked when the symbol is not provided in the command line input.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
`Option<T>` and `Argument<T>` classes now have a `DefaultValueFactory` property that can be used to set the default value for the symbol. This property is invoked when the symbol is not provided in the command line input.
`Option<T>` and `Argument<T>` classes now have a `DefaultValueFactory` property that can be used to set a delegate that can be called to get the default value for the option or argument. This delegate is invoked when the option or argument is not found in the parsed command line input.

};
```

## Default values
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## Default values
## Default values and custom parsing

};
```

Moreover, `CustomParser` accepts `Func<ParseResult, T>` delegate, rather than dedicated `ParseArgument` delegate. This and few other custom delegates were removed to simplify the API and reduce the number of types exposed by the API and compiled at startup time by the JIT compiler.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Moreover, `CustomParser` accepts `Func<ParseResult, T>` delegate, rather than dedicated `ParseArgument` delegate. This and few other custom delegates were removed to simplify the API and reduce the number of types exposed by the API and compiled at startup time by the JIT compiler.
Moreover, `CustomParser` accepts a delegate of type `Func<ParseResult, T>`, rather than the previous `ParseArgument` delegate. This and a few other custom delegates were removed to simplify the API and reduce the number of types exposed by the API, which reduces startup time spent during JIT compilation.


For more examples of how to use `DefaultValueFactory` and `CustomParser`, see the [How to customize parsing and validation in System.CommandLine](parsing-and-validation.md) document.

## The separation of parsing and invoking
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## The separation of parsing and invoking
## The separation of parsing and invocation


## The separation of parsing and invoking

In beta4, it was possible to separate the parsing and invoking of commands, but it was quite unclear how to do it. The `Command` was not exposing a `Parse` method, but `CommandExtensions` was providing `Parse`, `Invoke`, and `InvokeAsync` extension methods for `Command`. This was confusing, as it was not clear which method to use and when. Following changes were made to simplify the API:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In beta4, it was possible to separate the parsing and invoking of commands, but it was quite unclear how to do it. The `Command` was not exposing a `Parse` method, but `CommandExtensions` was providing `Parse`, `Invoke`, and `InvokeAsync` extension methods for `Command`. This was confusing, as it was not clear which method to use and when. Following changes were made to simplify the API:
In beta4, it was possible to separate the parsing and invoking of commands, but it was quite unclear how to do it. `Command` did not expose a `Parse` method, but `CommandExtensions` provided `Parse`, `Invoke`, and `InvokeAsync` extension methods for `Command`. This was confusing, as it was not clear which method to use and when. The following changes were made to simplify the API:


## Renaming

In beta4, not all types and properties followed the [naming guidelines](../design-guidelines/naming-guidelines.md). Some were not consistent with the naming conventions, such as using the `Is` prefix for boolean properties. In beta5, we have renamed some types and properties. The following table shows the old and new names:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In beta4, not all types and properties followed the [naming guidelines](../design-guidelines/naming-guidelines.md). Some were not consistent with the naming conventions, such as using the `Is` prefix for boolean properties. In beta5, we have renamed some types and properties. The following table shows the old and new names:
In beta4, not all types and members followed the [naming guidelines](../design-guidelines/naming-guidelines.md). Some were not consistent with the naming conventions, such as using the `Is` prefix for boolean properties. In beta5, we have renamed some types and members. The following table shows the old and new names:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps pedantic of me, but I recommend renaming this to 2.0.0-beta5 and generally referring to the release as 2.0.0-beta5 throughout.

Comment on lines +2 to +3
title: System.CommandLine beta5 breaking changes
description: "Learn what breaking changes were introduced in beta5 and why."
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
title: System.CommandLine beta5 breaking changes
description: "Learn what breaking changes were introduced in beta5 and why."
title: System.CommandLine 2.0.0-beta5 breaking changes
description: "Learn what breaking changes were introduced in 2.0.0-beta5 and why."

ms.topic: how-to
---

# Breaking changes in beta5
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Breaking changes in beta5
# Breaking changes in 2.0.0-beta5


## Renaming

In beta4, not all types and properties followed the [naming guidelines](../design-guidelines/naming-guidelines.md). Some were not consistent with the naming conventions, such as using the `Is` prefix for boolean properties. In beta5, we have renamed some types and properties. The following table shows the old and new names:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In beta4, not all types and properties followed the [naming guidelines](../design-guidelines/naming-guidelines.md). Some were not consistent with the naming conventions, such as using the `Is` prefix for boolean properties. In beta5, we have renamed some types and properties. The following table shows the old and new names:
In 2.0.0-beta4, not all types and properties followed the [naming guidelines](../design-guidelines/naming-guidelines.md). Some were not consistent with the naming conventions, such as using the `Is` prefix for boolean properties. In 2.0.0-beta5, we have renamed some types and properties. The following table shows the old and new names:


In beta4, it was possible to separate the parsing and invoking of commands, but it was quite unclear how to do it. The `Command` was not exposing a `Parse` method, but `CommandExtensions` was providing `Parse`, `Invoke`, and `InvokeAsync` extension methods for `Command`. This was confusing, as it was not clear which method to use and when. Following changes were made to simplify the API:

- `Command` now exposes a `Parse` method that returns a `ParseResult` object. This method is used to parse the command line input and return the result of the parsing. Moreover, it makes it clear that the command is not invoked, but only parsed and only in synchronous manner.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `Command` now exposes a `Parse` method that returns a `ParseResult` object. This method is used to parse the command line input and return the result of the parsing. Moreover, it makes it clear that the command is not invoked, but only parsed and only in synchronous manner.
- `Command` now exposes a `Parse` method that returns a `ParseResult` object. This method is used to parse the command line input and return the result of the parse operation. Moreover, it makes it clear that the command is not invoked, but only parsed and only in synchronous manner.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants