6

With a root command:

new RootCommand
{
    new Option<string>("--myoption")
};

how do you tell the difference between

./myapp

and

./myapp --myoption ""

?

I initially assumed that the option would be null if it wasn't specified, but it's not, it's an empty string :( Adding an explicit default of null also doesn't work; this code still prints out "" when no options are passed in:

static void Main(string[] args)
{
    var rootCommand = new RootCommand
    {
        new Option<string>("--myoption", () => null)
    };
    rootCommand.Handler = CommandHandler.Create<string>(Run);
    rootCommand.Invoke(args);
}

private static void Run(string myoption)
{
    Console.WriteLine(myoption == null ? "(null)" : '"' + myoption + '"');
}

If the default is set to a non-null string, the default does come through as expected; only null is mysteriously changed into an empty string.

Mark Raymond
  • 906
  • 8
  • 22

1 Answers1

2

You can describe a function to calculate a default value. If using C# 8 or newer, you may need to explicitly say that your string is nullable by adding the question mark at the end.

new RootCommand
{
    new Option<string?>("--myoption", () => null, "My option. Defaults to null");
};

I would have thought that this would work, but I was able to set up a working example on dotnetfiddle here https://dotnetfiddle.net/uxyC8Y which shows even with every parameter marked as nullable, it is still being returned as an empty string. This may be an issue with the System.CommandLine project, so I put in an issue here https://github.com/dotnet/command-line-api/issues/1459

EDIT: This issue was resolved just 2 days ago with this commit https://github.com/dotnet/command-line-api/pull/1458/files it will take some time before this fix shows up in a published NuGet package, but it will be fixed eventually in future versions of the library.

Without being able to use nulls, my only suggestion would be to use a very distinct default string to mark a value as not assigned.

const string defaultString = "Not Assigned.";
static void Main(string[] args)
{
    var rootCommand = new RootCommand
    {
        new Option<string>("--myoption", () => defaultString)
    };
    rootCommand.Handler = CommandHandler.Create<string>(Run);
    rootCommand.Invoke(args);
}

private static void Run(string myoption)
{
    Console.WriteLine(myoption == defaultString ? "(null)" : '"' + myoption + '"');
}
TJ Rockefeller
  • 3,178
  • 17
  • 43
  • I tried that; unfortunately with an explicit default of `null`, it still actually default to an empty string! If I have an explicit default of anything apart from `null`, then that works, but `null` does not. I will update the question. – Mark Raymond Nov 04 '21 at 09:49
  • @MarkRaymond are you using C# 8 with nullable references https://endjin.com/blog/2020/10/dotnet-csharp-8-nullable-references-empty-strings ? I think by default C# 8 will not allow null values, unless you explicitly say that nulls are allowed. I'll update my answer with what should fix it. – TJ Rockefeller Nov 04 '21 at 12:36