Being a longtime Perl programmer, I came to take the wonderful GetOpt::Long standard module for granted. Easily defining and parsing required and optional command-line parameters was as simple as defining an array of the parameters you expect and dumping them into a hash usable by the program.
So when I began writing command-line apps in C# 2.0, I was rather disappointed to discover how lacking that language is in processing command-line options in a usable way. After a futile Google search for a suitable replacement, I eventually stumbled upon the Mono.GetOptions library. (I use Visual Studio 2005, and not Mono, otherwise I probably would have come across this library sooner).
The result is something that is much more comfortable in C# than trying to store the passed options in some sort of array or hashtable. Instead, a custom class is defined to hold the options, which then uses Attributes and reflection to not only bind these parameters to the correct properties, but also to describe them in a sensible way to make usage-doc generation (the kind you see with --help) a snap.
Following is an example of how to use this library, taken from a similar post regarding this library. First, you need to import the necessary assemblies (adding references if necessary); this includes not only Mono.GetOptions but the required reflection assemblies as well:
using System;
using System.Reflection;
using Mono.GetOptions;
Then, in AssemblyInfo.cs, add some information about your assembly using Attributes. The stub code for this was probably already generated by Visual Studio when you created the project:
// Attributes visible in " --help"
[assembly: AssemblyTitle ("go.exe")]
[assembly: AssemblyVersion ("1.0.*")]
[assembly: AssemblyDescription ("Mono.GetOptions Sample Program")]
[assembly: AssemblyCopyright ("Public Domain")]
// This is text that goes after " [options]" in help output.
[assembly: Mono.UsageComplement ("")]
// Attributes visible in " -V"
[assembly: Mono.About("Insert About Text Here.")]
[assembly: Mono.Author ("Your name here")]
Next, create a class to store those options. The names of the properties in your class will be used as the names of the parameters from the command line; you must supply descriptions and “short” versions of these. Take note of the ParsingMode property, which allows you to specify which of the various command-parsing modes to use (GNU, Linux, Windows, or “Both” — not sure which “both” that one refers to!)
class SampleOptions : Options
{
// Long option is the variable name ("--file"), short option is -f
[Option ("Write report to FILE", 'f')]
public string file;
// Long option is the variable name ("--quiet"), short option is -q
[Option ("don't print status messages to stdout", 'q')]
public bool quiet;
// Long option is as specified ("--use-int"), no short option
[Option ("Sample int option", "use-int")]
public int use_int;
public SampleOptions ()
{
base.ParsingMode = OptionsParsingMode.Both;
}
}
And finally, a test program to use the options class:
class TestApp
{
public static void Main (string[] args)
{
SampleOptions options = new SampleOptions ();
options.ProcessArgs (args);
Console.WriteLine ("Specified Program Options:");
Console.WriteLine ("\t file: {0}", options.file);
Console.WriteLine ("\t quiet: {0}", options.quiet);
Console.WriteLine ("\t use_int: {0}", options.use_int);
Console.WriteLine ("Remaining Program Options:");
foreach (string s in options.RemainingArguments) {
Console.WriteLine ("\t{0}", s);
}
}
}
Some sample output:
C:\> go.exe --help
go.exe 1.0.1573.25851 - Public Domain
Mono.GetOptions Sample Program
Usage: go [options]
Options:
-f --file:PARAM Write report to FILE
-? --help Show this help list
-q --quiet don't print status messages to stdout
--usage Show usage syntax and exit
--use-int:PARAM Sample int option
--verbosegetoptions Show verbose parsing of options
-V --version Display version and licensing information
C:\> go.exe --V
go.exe 1.0.1573.25851 - Public Domain
Mono.GetOptions Sample Program
Insert About Text Here.
Authors:
Your name here
Specified Program Options:
file:
quiet: False
use_int: 0
Remaining Program Options:



Peter | 25-Jul-06 at 10:27 am | Permalink
I’m not familiar with Perl but I don’t see where C# lags behind in this area. You said in Perl you’d “define an array of the parameters you expect and dumping them into a hash usable by the program.” C# gives you an array (Main’s args argument in your code above) which you can then dump into a hash just as easily. What am I missing?
Hmm… One thing might be that what little command line processing I’ve done just takes in argument values, not the names of the arguments–so for example, I’d just specify “FILE_NAME” instead of “–f FILE_NAME”, because I haven’t had a need to write complex command line apps. Is the latter the sort of thing Perl does more easily?
That sample run doesn’t show off much of the program. The first shows the help text (which I agree is pretty cool and would take some ugly String.Concat-riffic code to reproduce), but neither shows options actually being parsed. And why doesn’t the first one output the Specified Program Options stuff? Does options.ProcessArgs kill the thread or something if you specify –help?
toby | 25-Jul-06 at 10:43 am | Permalink
Well, the base assumption I made here is that anyone looking for this type of info would already be familiar with the ubiquitous getopt-style parameter processing common to Perl scripts[1], GNU programs[2], and other such “Unix-y” utilities, so I didn’t expand on that much.
Main’s args isn’t an array of parameters you expect. It’s an array of parameters that the user entered on the command line. C# does nothing in the way of making those parameters easily usable, or making it easy to find if the user entered extra parameters you don’t want. For example, it’s very common in command line programs to have an option called “quiet” to suppress most output. With just args, you’d have to iterate through the whole array to look for that parameter and repeat that for every other parameter you might expect.
That’s fine if you’re just expecting the name of an input file or something, but not if you have a half dozen or more different options the user can specify. These options generally fall into two categories, which are boolean switches (e.g. “quiet” above) where the user either specified it (true) or not (false); or input parameters that take a value (e.g. input file, processing date, etc.)
When you get enough of those, it’s not very user-friendly to require that they be passed in some specific order, thus the need for attaching them to specific names. Typically these names always have a “long” version, such as “quiet”, while the most commonly-used ones have a “short” version as well, usually just the first letter.
I agree that the examples aren’t the greatest; I’ll update it more once I get a working program (I mostly just copied what I found on the post I referenced). But I thought it was pretty clear that the options simply got bound to the members of SampleOptions; again that might assume someone who has already used the getopt-type processing previously.
[1]http://search.cpan.org/~jv/Getopt-Long-2.35/lib/Getopt/Long.pm
[2]http://www.gnu.org/software/libc/manual/html_node/Getopt.html
Guillaume | 27-Jul-06 at 2:41 am | Permalink
I discovered this Mono.GetOptions by using Softec’s SubversionSharp ( as well as your website ).
Powerful indeed !
Talking about SubversionSharp ( and Svn.Net ), please write some documentation about the functionalities as well as exemples on using it, cause so far thats the only thing i miss badly using those projects.
But as Denis told me, i can use the C Svn Documentation of course, but that wont help me a lot personally if i dont have the specific exemples.
Anyway, keep us informed of how the project is going and keep the good work ;)
toby | 27-Jul-06 at 9:30 am | Permalink
That’s actually how I discovered the Mono.GetOptions as well. More info will be forthcoming on Svn.NET; I am waiting until the 1.4.0 Subversion libs are officially released and then I will try to put up complete documentation as well as a compiled set of Svn.NET, dynamically linked svn libs, and any other DLLs necessary.
Aurel Sarac | 13-Sep-06 at 2:31 pm | Permalink
I also happen to like Perl’s Getopt::Long, but I like even more App::Options which finds options not only on the command line, but also in config files and environment.
I was just wondering if anyone ‘bumped’ into something similar in C#.
Thanks,
Aurel
toby | 13-Sep-06 at 2:44 pm | Permalink
No, I haven’t seen anything similar in C#, and I had never even heard of App::Options in Perl. Although looking at its CPAN documentation, I really wish I had found that module before! My old employer used environment variables, command-line parameters (due to lots of scheduler-based shell/batch scripts), and often .ini files all with the same program, and combining all those options was sometimes a real pain. Looks like App::Options makes that task much easier.