2

I am trying to use System.CommandLine and I haven't been able to get my handler to see any of the values that I'm passing in. I've tried the simplest command line program just to see if any values make it through and so far I haven't been successful. I am targeting .NET 4.7.2 and I'm using System.CommandLine 2.0.0-beta1.20574.7

    using System;
    using System.CommandLine;
    using System.CommandLine.Invocation;

    static class Program
    {
        public static void Main(string[] args)
        {
            var rootCommand = new RootCommand
            {
                new Option("--continue", "continue option")
            };

            rootCommand.Description = "Testing System.CommandLine";

            rootCommand.Handler = CommandHandler.Create<bool>
                ((willContinue) => run(willContinue));

            rootCommand.Invoke(args);
        }

        private static void run(bool willContinue)
        {
            Console.WriteLine(willContinue);
        }
    }

No matter how I call my application, I am not seeing the value of willContinue come across as true.

myapp.exe --continue -> False

myapp.exe --cont -> Unrecognized command or argument '--cont' (my options are at least getting recognized)

myapp.exe --continue true -> Unrecognized command or argument 'true'

myapp.exe --help ->

myapp:
Testing System.CommandLine

Usage:
myapp [options]

Options:
--continue continue option
--version Show version information
-?, -h, --help Show help and usage information

TJ Rockefeller
  • 3,178
  • 17
  • 43

2 Answers2

3

You need to fix 2 things:

  1. add the option type, which is bool
  2. change the name of the option to match the parameter name

the following command works:

var rootCommand = new RootCommand
{
    new Option<bool>("--willContinue", "continue option")
};

and call it like so

myapp.exe --willContinue true

the option name and parameter name don't always have to match-up, but in this case it doesn't work because 'continue' is a reserved word

Lev
  • 583
  • 3
  • 15
  • it looks like the key thing is that the option name has to match the parameter name. It works with just a plain Option instead of `Option` which defaults to a bool flag type option. I changed the name of my parameter to willContinue because continue is a C# keyword, and that's where things broke down for me. Thanks. – TJ Rockefeller Feb 03 '21 at 21:52
  • 1
    It does look like the option name and the parameter name do need to match. I tried with an option name of "willContinue" and a parameter name of "something" and it didn't come across with the correct value. – TJ Rockefeller Feb 03 '21 at 21:57
  • When targeting net5 I get the opposite result: when I don't specify the type I get the error ```Unrecognized command or argument 'true'``` but I can change method parameter name to ```something``` and it still works. Explains why it's still in beta, and I guess it's good practice to follow both rules: keep same name and specify the option type – Lev Feb 03 '21 at 22:04
  • If you are using a plain option without a type, then the usage is `myapp.exe --willContinue` and you don't specify true or false. If the option is present, then the value comes across as true and if it's not present, then it comes across as false which is what I was wanting. – TJ Rockefeller Feb 03 '21 at 22:06
2

I wanted to add an answer to be very clear about exactly what resolved my problem

using System;
using System.CommandLine;
using System.CommandLine.Invocation;

static class Program
{
    public static void Main(string[] args)
    {
        var rootCommand = new RootCommand
        {
            new Option("--willContinue", "continue option")
            //             ^This option name
        };

        rootCommand.Description = "Testing System.CommandLine";

        rootCommand.Handler = CommandHandler.Create<bool>
            ((WiLLCoNtInUe) => run(WiLLCoNtInUe));
        //     ^ HAS to match this parameter name where the command handler is created.
        //       but does not have to match case

        rootCommand.Invoke(args);
    }
 
    private static void run(bool canBeSomethingElse)
    // Because of how this is called ^ this does not have to match
    {
        Console.WriteLine(canBeSomethingElse);
    }
}

Because the Argument/Option/Command/anything else that can be added to a Command object has to match the name of the parameter used when creating the CommandHandler, the names used can't have spaces, begin with numbers, or use a C# keyword (not having spaces is not a problem for most items because it would be silly/impossible to have an option --will continue, but with arguments you don't have to put the name of the argument into your command line call because it is listed in the usage as <argument name> and the argument is read in by position, so I was wanting to use an argument name like <file directory>, but that doesn't work because you can't have a variable name with spaces in it)

TJ Rockefeller
  • 3,178
  • 17
  • 43
  • 1
    you can use c# keywords as parameter names: `rootCommand.Handler = CommandHandler.Create((@continue)=>run(@continue))` (see [link](https://stackoverflow.com/questions/2787716/use-the-long-reserved-word-as-a-variable-name-in-c-sharp)) – Martin Feb 18 '21 at 15:44