Search code examples
c#system.commandline

System.CommandLine argument not being passed to handler


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);
        }
    }
}

Solution

  • 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