When I released version 3.0 of Ookii.CommandLine last year, I wasn't expecting to have another major release so soon. I still had some ideas for new features, like supporting automatic aliases based on prefixes of command line arguments, but they'd only warrant minor revisions.
But then, I started reading about .Net source generators, and I thought, that's something I could use. Ookii.CommandLine used reflection to determine the command line arguments at runtime, so a source generator would be able to do the same job at compile time. That would make it faster, make the library trim-friendly, and allow me to emit warnings and errors for unsupported argument settings, define positional arguments based on the order of the class members rather than explicit numbers, and extract default values from property initializers.
Ookii.CommandLine 4.0 now gives you that option. You can apply the
GeneratedParserAttribute
to any class that defines command line arguments, and the parser will
be generated at compile time.
[GeneratedParser] partial class MyArguments { [CommandLineArgument(IsPositional = true)] [Description("A required positional argument.")] public required string Required { get; set; } [CommandLineArgument(IsPositional = true)] [Description("An optional positional argument.")] public int Optional { get; set; } = 42; [CommandLineArgument] [Description("An argument that can only be supplied by name.")] public DateTime Named { get; set; } [CommandLineArgument] [Description("A switch argument, which doesn't require a value.")] public bool Switch { get; set; } }
That still might not have warranted a major version bump, if trimming hadn't been a goal.
Ookii.CommandLine relied on the TypeConverter
class to convert argument values from strings to
their defined type, and I soon discovered that determining the right TypeConverter
for any
type at compile time wasn't really possible, and calling TypeDescriptor.GetConverter()
at
runtime was inherently not compatible with trimming an application. I guess this is why
System.CommandLine limits their supported types to just a chosen handful, and everything else
requires custom converters.
The solution was ArgumentConverter
, a new way to convert argument values, that replaces
TypeConverter
. Not only is it trim-friendly, it also enables converting arguments using
ReadOnlySpan<char>
, which means that the parser can avoid allocating strings when splitting
arguments provided like -Name:value
, another performance improvement.
However, it does mean that any command line arguments classes that relied on a TypeConverter
will no longer function correctly without modifications, so the major version needed to change
again. While I was at it, I made a few other breaking changes, the biggest of which was probably the
removal of constructor parameters as a way to define command line arguments. Now, properties and
methods are your only choice. I was never a big fan of the way constructor parameters worked, and
how clumsy it was to add attributes to them. They were already de-emphasized in the documentation,
and were mostly left over from version 1.0 (sadly lost to time), where they were the only way to
define positional arguments. The work needed to support them with source generation meant they ended
up on the chopping block this time.
For these and other breaking changes, check the migration guide. As with version 3.0, most users probably won't need to make many changes.
Besides source generation and new argument converters, Ookii.CommandLine 4.0 gives you plenty of
other goodness, including the aforementioned automatic prefix aliases, support for C# 11 required
properties, a new attribute for value descriptions that allows for localization, canceling parsing
with success and access the remaining arguments afterwards, support for nested subcommands, source
link integration, and more.
See the change log for everything that's new.
Get it on NuGet or GitHub. You can also try out the parser or subcommands on .Net Fiddle.
No comments here...
Comments are closed for this post. Sorry.