When you have defined the command line arguments, you can parse the command line to determine their values. There are two basic ways to do this, described below.
The easiest way to parse the arguments is using the static Parse()
methods that are
generated for your arguments class when using source generation with the
GeneratedParserAttribute
. These methods take care of parsing the arguments, handling errors,
and printing usage help if necessary.
A basic usage sample for the CommandLineParser
class is as follows:
public static int Main()
{
var arguments = MyArguments.Parse();
if (arguments == null)
{
return 1; // Or a suitable error code.
}
return RunApplication(arguments);
}
This overload takes the arguments from the Environment.GetCommandLineArgs()
method, so there is
no need to pass them manually (though you can if desired), and the default ParseOptions
.
If you cannot use source generation, you can call one of the CommandLineParser.Parse<T>()
methods, which work the same way as the generated method.
If argument parsing is successful, the CommandLineParser
will create a new instance of the
class defining the arguments. It will then set the value of each property to the value of the
corresponding argument. This is not done in any particular order, so do not write code that makes
assumptions about this. Finally, it will return the instance.
Argument parsing can fail for a number of reason, including:
- Not all required arguments were specified.
- An argument name was supplied without a value for an argument that’s not a switch
- An unknown argument name was supplied
- A non-multi-value argument was specified more than once
- Too many positional argument values were supplied
- Argument value conversion failed for one of the arguments.
- An argument failed validation.
See the CommandLineArgumentErrorCategory
enumeration for more information. In addition,
parsing could have been canceled by an argument using the
CommandLineArgumentAttribute.CancelParsing
property with CancelMode.Abort
, a method
argument, or the automatic -Help
and -Version
arguments.
If argument parsing does fail or was canceled, the generated Parse()
method (as well as the static
CommandLineParser.Parse<T>()
method) returns null. The method has already printed error and
usage information, and there's nothing you need to do except exit your application.
The generated Parse()
methods and the static Parse<T>()
method will never throw
a CommandLineArgumentException
. They can throw other exceptions if the arguments type violates one
of the rules for valid arguments (such as defining an optional positional argument after a required
one). An exception from this method typically indicates a mistake in your arguments class. When
using source generation, these kinds of errors are often caught at compile time.
You can customize various aspects of the parsing behavior using either the
ParseOptionsAttribute
, applied to your arguments class, or a ParseOptions
instance
passed to the Parse()
method. The latter can be used to set a few options not available with the
ParseOptionsAttribute
, including options to customize the usage help and error messages.
The ParseOptions
class can even be used to redirect where errors and help are written.
using var writer = LineWrappingTextWriter.ForStringWriter();
var options = new ParseOptions()
{
Error = writer,
IsPosix = true,
DuplicateArguments = ErrorMode.Warning,
UsageWriter = new UsageWriter(writer);
};
var arguments = MyArguments.Parse(options);
if (arguments == null)
{
// There are probably better ways to show help in a GUI app than this.
MessageBox.Show(writer.ToString());
return 1;
}
If you wish to customize the error messages shown to the user if parsing fails, for example to
localize them, you can do that using the LocalizedStringProvider
class. This class is used as
the source for all error messages, as well as a number of other strings used by Ookii.CommandLine.
Create a class that derives from the LocalizedStringProvider
class and override its members to
customize any strings you wish to change. You can specify a custom string provider using the
ParseOptions.StringProvider
class. Localizing some strings used in the usage help may also
require you to create a custom UsageWriter
.
Alternatively, if you need more error information, you can use the manual parsing method below, and
use the CommandLineArgumentException.Category
property to determine the cause of the exception
and create your own error message.
The generated Parse()
methods and the static Parse<T>()
method and
their overloads will likely be sufficient for most use cases. However, sometimes you may want even
more fine-grained control. This includes the ability to handle the ArgumentParsed
and
DuplicateArgument
events, and to get additional information about the
arguments using the Arguments
property or the GetArgument
function.
In this case, you can manually create an instance of the CommandLineParser<T>
class. Then, call
the instance ParseWithErrorHandling()
or Parse()
method.
The
CommandLineParser<T>
class is a helper class that derives fromCommandLineParser
and provides strongly-typedParse()
andParseWithErrorHandling()
methods.
If you are using source generation, you can call the generated CreateParser()
method that is added
to your class to get a CommandLineParser<T>
instance. Otherwise, simply use
new CommandLineParser<MyArguments>()
.
Using ParseWithErrorHandling()
is the easiest in this case, because
it will still handle printing error messages and usage help, the same as the generated Parse()
method and static Parse<T>()
methods. If you want more information about the error
that occurred, you can access the CommandLineParser.ParseResult
property after parsing.
For example, you can use this approach if you want to return a success status when parsing was canceled, but not when a parsing error occurred:
var parser = MyArguments.CreateParser();
var arguments = parser.ParseWithErrorHandling();
if (arguments == null)
{
return parser.ParseResult.Status == ParseStatus.Canceled ? 0 : 1;
}
The status will be set to ParseStatus.Canceled
if parsing was canceled with CancelMode.Abort
.
You can also use the ParseResult.ArgumentName
property to determine which argument canceled
parsing in this case. If an error occurred, the status will be ParseStatus.Error
and you can
use the ParseResult.LastException
property to access the actual error that occurred.
If parsing was canceled using CancelMode.Success
, the status will be ParseStatus.Success
, but
ParseResult.ArgumentName
will be non-null and set to the argument that canceled parsing. Use the
ParseResult.RemainingArguments
property to get any arguments that were not parsed.
For the most fine grained control, you can use the CommandLineParser<T>.Parse()
method, which
lets you handle errors manually.
If argument parsing fails, the instance CommandLineParser<T>.Parse()
method will throw a
CommandLineArgumentException
exception, which you need to handle. You can simply print the
exception message, or check the CommandLineArgumentException.Category
property to determine
the cause of the error.
The non-static Parse()
method returns null only if parsing was canceled. This also
happens if the automatic -Help
or -Version
arguments were used.
The automatic -Help
argument implementation doesn't actually show help; it relies on the caller to
do so. However, if the Parse()
method returns null, it does not necessarily mean
that you should display usage help. For example, the automatic -Version
argument cancels parsing,
but should typically not result in a help message.
To see whether you should show usage help, check the HelpRequested
property. This property
will always be true if an exception was thrown, and always be false if the
Parse()
method returned an instance.
If the Parse()
method returned null, you can also check the
CommandLineParser.ParseResult
property to see which argument canceled parsing.
Here is a basic sample of manual parsing and error handling using the Parse()
method:
static int Main()
{
var parser = MyArguments.CreateParser();
try
{
var arguments = parser.Parse();
if (arguments != null)
{
return RunApplication(arguments);
}
}
catch (CommandLineArgumentException ex)
{
Console.Error.WriteLine(ex.Message);
}
if (parser.HelpRequested)
{
parser.WriteUsage();
}
return 1;
}
If you wish to customize the behavior, that can still be done using the ParseOptionsAttribute
attribute and the ParseOptions
class (which you can pass to the CommandLineParser<T>
constructor or the generated CreateParser()
method). Some properties of the ParseOptions
class (like Error
) are not used with the Parse()
methods, as they apply to the
ParseWithErrorHandling()
and the static Parse<T>()
methods only.
Next, we'll take a look at generating usage help.