2

I'm trying to get to grips with System.CommandLine.

I can parse boolean options on the commandline such as -x and I can pass string options, eg -f myfile however what I'm having trouble with is the string argument that can optionally be passed to the program- not as an option.

The parser is on some level understanding the argument. If I provide zero or one strings on the commandline then there's no error. If I provide an extra string then I get the error "Unrecognized command or argument". In the handler, however, the parameter is always null. Even if I've specified a default and not marked the string as nullable.

The sandpit code I'm working with is below. Can anyone suggest what I'm doing wrong? I've found lots of discussion elsewhere about Options, but rather less about Arguments.

using System.CommandLine;
using System.CommandLine.IO;
using System.CommandLine.NamingConventionBinder;

namespace ConsoleApp1
{
    public static class Program
    {
        public static int Main(string[] args)
        {

            RootCommand _cmd = new()
             {
                 new Option<bool>(new[] { "--immediatecalc", "-c" }, () => { return false; }, "Automatically run calculations when a file is loaded"),
                 new Option<bool>(new[] { "--autoexit", "-x" }, () => { return false; }, "Exit after carrying out directed tasks"),
                 new Option<bool>(new[] { "--saveJSON", "-s" }, () => { return false; }, "Export on deck JSON file after calculating"),
                 new Option<string?>(new[] { "--JSONfile", "-f" }, () => { return null; }, "File name for exported JSON file"),
                 new Argument<string?>("Filename", () => { return null; }, "The file to load.")
            };

            _cmd.Handler = CommandHandler.Create<bool, bool, bool, string?, string?, IConsole>(Handler);

            return _cmd.Invoke(args);
        }
        static void Handler(bool immediatecalc, bool autoexit, bool saveJSON, string? jsonFile, string? sourceFile, IConsole console)
        {
            console.WriteLine("Immediate calc " + immediatecalc);
            console.WriteLine("Autoexit " + autoexit);
            console.WriteLine("saveJSON " + saveJSON);
            console.WriteLine("Json file is " + jsonFile);
            console.WriteLine("Source file is " + sourceFile);
        }
    }
}
Craig Graham
  • 1,161
  • 11
  • 35
  • What version of System.CommandLine are you using? I believe there is a newer version of System.CommandLine that uses a different handler syntax `_cmd.SetHandler(...)` – TJ Rockefeller Mar 23 '22 at 13:16
  • most likely the reason this code isn't working is because in the previous style of `CommandHander.Create` things got mapped to the handler through some kind of magical reflection logic that matched parameter names with the names of your options and arguments. I wouldn't bother trying to get this to work since the newer version is a lot more explicit in how things get mapped and parameter names don't have to match for things to work. – TJ Rockefeller Mar 23 '22 at 13:40

1 Answers1

1

This is how I would set it up using the latest System.CommandLine version 2.0.0-beta3.22114.1

using System.CommandLine;

namespace ConsoleApp1
{
    public static class Program
    {
        public static int Main(string[] args)
        {

            var immediateCalcOption = new Option<bool>(new[] { "--immediatecalc", "-c" }, () => { return false; }, "Automatically run calculations when a file is loaded");
            var autoExitOption = new Option<bool>(new[] { "--autoexit", "-x" }, () => { return false; }, "Exit after carrying out directed tasks");
            var saveJsonOption = new Option<bool>(new[] { "--saveJSON", "-s" }, () => { return false; }, "Export on deck JSON file after calculating");
            var jsonFileOption = new Option<string?>(new[] { "--JSONfile", "-f" }, () => { return null; }, "File name for exported JSON file");
            var fileNameArgument = new Argument<string?>("Filename", () => { return null; }, "The file to load.");
            RootCommand _cmd = new()
            {
                immediateCalcOption,
                autoExitOption,
                saveJsonOption,
                jsonFileOption,
                fileNameArgument
            };

            _cmd.SetHandler<bool, bool, bool, string?, string?, IConsole>(Handler, immediateCalcOption, autoExitOption, saveJsonOption, jsonFileOption, fileNameArgument);

            return _cmd.Invoke(args);
        }
        static void Handler(bool immediatecalc, bool autoexit, bool saveJSON, string? jsonFile, string? sourceFile, IConsole console)
        {
            console.WriteLine("Immediate calc " + immediatecalc);
            console.WriteLine("Autoexit " + autoexit);
            console.WriteLine("saveJSON " + saveJSON);
            console.WriteLine("Json file is " + jsonFile);
            console.WriteLine("Source file is " + sourceFile);
        }
    }
}

this worked for me with the args input filename -c -x -s -f hello gave me this output

Immediate calc True
Autoexit True
saveJSON True
Json file is hello
Source file is filename

TJ Rockefeller
  • 3,178
  • 17
  • 43