Argopt: Command line argument parsing in .NET[source]

xml
<glacius:metadata>
    <title>Argopt: Command line argument parsing in .NET</title>
    <description>Introduction post for my CLI argument parsing library for .NET</description>
    <category>Legacy blog posts</category>
    <category>Programming</category>
    <category>C#</category>
</glacius:metadata>
<glacius:macro name="legacy blargh banner">
    <properties>
        <originalUrl>https://tmont.com/blargh/2011/5/argopt-command-line-argument-parsing-in-net</originalUrl>
        <originalDate>2011-05-11T22:51:05.000Z</originalDate>
    </properties>
</glacius:macro>
<p>
  So, I was writing a console app in C# the other day, and I needed to parse some command 
  line arguments. A quick google search gave me 
  <a href="http://www.ndesk.org/Options">NDesk.Options</a>, which I've used before. 
  However, it's quite old. Whenever I see a .NET project that talks about using "new" 
  features like lambda expressions, I get a little wary. It also doesn't help that the 
  author and maintainer of the project claims it is <em>UNSTABLE</em>, and hasn't been 
  updated since 2008.
</p>
<p>So, I wrote my own.</p>
<p>
  This isn't new territory for me: I wrote one in PHP before the 
  dawn of PHP 5.3 and platform-independent <a href="https://www.php.net/getopt">getopt</a>. 
  And I thought it would be fun.
</p>
<p>
  I also didn't really like the API of NDesk: too many magic strings, and the code was very 
  imperative. I want objects and generics and attributes and angle brackets, dammit.
</p>
<p>
  Introducing <strong><a href="https://argopt.tmont.com/">Argopt</a></strong>, another
  command line argument parsing library. And shut up, I like the name. It sounds like
  a Greek warrior.
</p>
<p>What you do is:</p>
<ol>
  <li>define the command line arguments in a class (a <em>contract</em>)</li>
  <li>annotate the properties in that class with some special attributes</li>
  <li>
    Argopt uses that class definition to figure out how to parse things and 
    returns an instance of that class with the command line values injected
  </li>
</ol>
<p>Here's the example from the main site:</p>
<glacius:code lang="csharp"><![CDATA[using System;
using Argopt;
// this will handle things like:
//   greeting.exe --names=Bill,Hillary,Barack,Michelle -r 1 "What a nice day"
//   greeting.exe -n Bill,Hillary,Barack,Michelle --repeat=1 "What a nice day "
//   greeting.exe /Names:Bill,Hillary,Barack,Michelle /r 1 "What a nice day"
public class MyContract {
	[ValueProperty]
	[Description("The greeting to display")]
	public string Greeting { get; set; }
	
	[Alias("r")]
	[Description("The number of times to repeat the greeting", ValueName = "times")]
	public int Repeat { get; set; }
	
	[Delimited(","), Alias("n")]
	[Description("The names of the people to greet", Required = true, ValueName = "name1,name2...")]
	public string[] Names { get; set; }
}
class Program {
	static void Main(string[] args) {
		var result = OptionParser.Parse<MyContract>(args);
		if (!result.IsValid) {
			foreach (var error in result.Errors) {
				Console.WriteLine(error.ThrownException);
			}
			
			return;
		}
		
		var contract = result.Contract; // this is an instance of MyContract
		
		if (contract.Names.Length == 0 || string.IsNullOrEmpty(contract.Greeting)) {
			// print usage
			Console.WriteLine(OptionParser.GetDescription<MyContract>());
			return;
		}
		
		foreach (var name in contract.Names) {
			for (var i = 0; i < contract.Repeat; i++) {
				Console.WriteLine(string.Format("{0}, {1}!", contract.Greeting, name));
			}
		}
	}
}]]></glacius:code>
<p>
  More information can be found at the website:
  <a href="https://argopt.tmont.com/">argopt.tmont.com</a>.
</p>