[TOC]
(Hopefully) easy to use declarative argument parser for C#.
We strive to create an argument parser with an easy set up. We want for definition of parser to take only a page of code and be close to just defining a class. We also want to avoid having a secondary API for retrieval of parsed data. To achieve this we needed to connect the definitions of options with with their retrieval and usage. We decided to let the user define how they will be fetching and using the parsed data by creating their own parser class with class fields representing data. So to use the parsed data user just needs to access a certain field in their parser class.
To connect parser with option definitions and parser configuration, annotations with Attributes are used. Our library processes the annotations on initialization, then creates an inner data structure to represent the user defined parser. During argument parsing it uses this data structure to interpret incoming tokens as user defined options. Results of parsing are then saved into the fields of the parser class where user can access them.
To use automatic argument parsing, define a class representing the parsed arguments. 🌊🦈 will populate this object with data from the command line.
- Create a class that represents arguments of your command (must be child of CShargs.Parser class)
- Properties or methods in the class correspond to command options. Annotate them with attributes to specify kinds of options.
- Parameters of an option are specified in attribute constructor.
- To parse arguments, create an instance of this object and call the CShargs.Parser.Parse() function, passing command line arguments to it.
class MyCommandArguments : CShargs.Parser {
// ... options go here
}
static void Main(string[] argv) {
var arguments = new MyCommandArguments();
arguments.Parse(argv);
}
- Parsed options and their parameters will be filled in the fields of the class instance.
- Plain arguments can be found in PlainArgs property as a list of strings.
When parsing fails, appropriate CShargs.ParsingException
is thrown. It contains autogenerated error message. See \ref ParsingExceptions for details.
If you implement custom option/type, you can throw FormatException
or OverflowException
to signal to the parser that the parsing has failed. Similarly, you can call standard
parsing methods, ie int.Parse
, Convert.To...
, because they throw these exceptions on parsing failure.
If your parser configuration contains a conflict, CShargs.ConfigurationException
is thrown at parser initialisation time.
See lists of:
- \ref OptionAttributes "all option types"
- \ref ParsingExceptions "all exceptions thrown during parsing"
See CShargs.FlagOptionAttribute
Flag option attribute is used for options without parameters. The type of the property must be bool.
\dontinclude TimeExample.cs \skip "verbose" \until }
For full example see \ref TimeExample.cs
See CShargs.ValueOptionAttribute
Value option attribute is used for options with parameters. Type of the option property must be either:
- one of the C# primitives (
int
,string
,bool
,short
,long
, etc.) - an enum. Entries are case sensitive, if LongCaseInsensitive setting is not set.
- any user defined type
T
, which provides static methodT Parse(string str);
\dontinclude TimeExample.cs \skipline format \skipline *
\skip "format" \until }
See CShargs.VerbOptionAttribute
Verb option attribute is used for subcommands. In this case, type of the option property must be a child of the CShargs.Parser
class.
\dontinclude GitExample.cs \skip "push" \until }
See CShargs.CustomOptionAttribute
If you need an option that needs some context during its own parsing, or you need to interpret the raw arguments in slightly different way, you can use the CustomOption
attribute on a method.
The signature of the method should be void MyMethod(string value)
.
If the custom parameter has a value attached to it (like this: --param=value
), it is given via the string value
parameter of the method. Otherwise the parameter is null
.
\dontinclude CustomExample.cs \skip // \until } \until }
See CShargs.ParserConfigAttribute
You can change the default parser configuration by annotating your parser class with parser config attribute.
In default configuration parsing is case sensitive and all syntax variants for writing options are allowed.
- aggregating short options ie. -abc / -a -b -c
- syntax of option parameters ie. -c 123 / -c123 / -c=123
Use CShargs.OptionFlags to forbid unwanted syntax variants.
Each option allows you to define one mandatory name and one optional short alias.
In addition to that you can set more aliases using CShargs.AliasOptionAttribute
, like this:
[AliasOption("R", nameof(Recursive))]
[AliasOption("a", nameof(Recursive), nameof(Force))]
class MyArguments : Parser {
[FlagOption("recursive", shortName: 'r')]
bool Recursive { get; set; }
[FlagOption("force", shortName: 'f')]
bool Force { get; set; }
// option -a is now equivalent to -rf and -Rf
}
You have to use property names of the aliased options. If you wont use them, you will get an exception on parser initialization.
Keep in mind, that the parser class can be annotated with multiple CShargs.AliasOptionAttribute
attributes. Also, you can create one alias for multiple flag options.
See CShargs.OptionGroupAttribute
If you want to force the user to select one of a list of options, use the group option attribute.
Again, use property names to reference other options.
The group must not contain any required options or any option dependencies, otherwise CShargs.ConfigurationException
is thrown on initialization.
\dontinclude GroupExample.cs \skip OptionGroup \until // \until }
You can specify that some options are available only when other options are present.
Use the useWith
argument in your option attribute which takes the option property name.
class MyArguments : Parser {
[FlagOption("print", shortName: 'p', help: "Print out progress")]
bool Print { get; set; }
[FlagOption("verbose", shortName: 'v', help: "Print more details", useWith: nameof(Print))]
bool Verbose { get; set; }
// if -v is used without -p parameter, an exception is thrown
}