If you’ve ever had to write a console application, you’ve probably always just quickly hacked together a command line parser. This is fine when you are the only person who is using the application, because you implicitly understand that the inputfile should be declared after the outputfile. Try explaining this wisdom to your colleague who just blew away their config file they had been working on for the last couple of hours beause they got the arguments the wrong way around :) Or, even worse, WYouWroteThisCode syndrome, where you realise the incompetent programmer who put the parameters this weird way around was you several years ago.

Fortunately, CSharpOptParse comes to the rescue. If you’ve ever played with Perl (who hasn’t?) it’s based on GetOpt, one of the best command line processing libraries in existance. Basically, you define a really simple object to store all your paramers (Very simple, comments axed for brevity on web):

public class Arguments
{
   
public string InputFile { get; set; }
   
public string OutputFile { get; set; }
}

Then by using attributes, you define how to map the command line on to each of these parameters:

[ShortOptionName('i')]
[
LongOptionName("input-file")]
[
UseNameAsLongOption(false)]
[
OptDef(OptValType.ValueReq)]
[
Category("Files")]
[
Description("The input file to process.")]
public string InputFile { get; set; }

So pretty straight forward right? Then all you need to do is the following magic to parse the parameters:

Arguments arguments = new Arguments();
Parser p = ParserFactory.BuildParser(arguments);
// Parse the args
args = p.Parse(args);

The parse takes all kinds of other options, such as to use – (unix) style or / (windows) style for specifying parameters. It also supports populating items from the enivronment if they are not specified on the command line – cool :) Oh, and if you want to suppot multiple options like I do in TestListGenerator, all you need to do is use a StringCollection, and tell the Parser about it via attributes:[ShortOptionName('i')]
[
LongOptionName("include")]
[
UseNameAsLongOption(false)]
[
OptDef(OptValType.MultValue, ValueType = typeof(string))]
[
Description("A list of categories that should be included in the test list generated. NB: You can define multiple categories by repeating the parameter - see examples.")]
[
Category("Criteria")]
public StringCollection IncludedCategories = new StringCollection();

NB: Note the gotchya – you need to make sure the StringCollection is instantiated.As a little bonus, there is also a really easy way to generate usage information (works like an XmlTextWriter):UsageBuilder usage = new UsageBuilder();
usage.GroupOptionsByCategory =
true;
usage.BeginSection(“Name”);
usage.AddParagraph(
“tlg.exe  – Test List Generator for Visual Studio”);
usage.EndSection();

// Generate the list of arguments and descriptions automagically
usage.BeginSection(“Arguments”);
usage.AddOptions(p);
usage.EndSection();

So there you have it – a simple but elegant solution to your command line woes. Slowly but surely, your code will become less arcane – you’ll thank your past self later.