NDesk.Options: getopt for C#

When writing software there are a number of problems which start off simple — simple enough to knock up your own solution — but usually blossom into something much more complex over time.

Logging is one such problem. It starts off with a simple three-liner function using File.AppendText(), but as requirements grow, you need to add things like timestamps, thread-safety, differentiating errors vs informational messages, archiving, and logging to a database. Before you know it, your three-liner logging function has blossomed into a very poor implementation of log4net.

I’ve seen this sort of thing happen often with teams that haven’t had much exposure to open-source library development, but get excited at the opportunity to create some reusable components of their own (which is why you should always be immediately suspicious of internal ‘common’ libraries and ‘custom frameworks’).

The trick is to recognize when the burden of maintaining a home-brew solution no longer makes sense versus integrating an existing library.

In business this is known as build versus buy, and there are of course some situations when it is smarter to build. For example if there are no third-party libraries available in your problem space, or they are immature, or no longer maintained, or they are encumbered with costs/licensing restrictions. Or sometimes you may prefer a unique implementation that actually is better. But all these should be at least recognized and considered before making a decision.

A simple example of this came up last week, when I was developing a command-line tool for running common user scenarios against our system for benchmarking purposes.

One of the intended goals was that we be able to script it into a post-build process, so command-line options were required for verbose logging, repeating scenarios over and over, whether or not to ignore errors, and of course which scenario to run.

Now, like logging, command-line options are not exactly rocket-science. This sort of code is perfectly acceptable:

if (args.Contains("/v")){    // verbose mode enabled}

However this can easily spiral into something far more complex with positional parameters, optional arguments, validation, options that cancel each other, defaults, long options, not to mention supporting both slashes and hyphens.

For this benchmark tool I didn’t even bother writing my own — having used getopt for C and Boost Program Options for C++ in a previous life, I set off immediately to find something similar for .NET.

I ended up selecting NDesk Options, an open-source library for parsing command-line options. It comes from the unix/mono side of .NET where bash still rules supreme, so you know it’s got to be good. And it is. With lambda-based callbacks for each option, and support for just about every command-line switch style known to man, I had the following knocked up in a few minutes:

All that help text is generated automatically for minimal effort. Cool!