commandline icon indicating copy to clipboard operation
commandline copied to clipboard

Value not available after Pasring

Open dpparekh opened this issue 8 years ago • 8 comments

I am doing the following thing in my code but there is a compile time error that Value isn't part of result.

static void Main(string[] args) { var result = Parser.Default.ParseArguments<Options>(args); var x = result.Value.SomeArg }

What am I missing?

dpparekh avatar Jan 18 '17 20:01 dpparekh

You need to use the generic version of the ParseArguments method, otherwise the parser doesn't know what kind of arguments are available to parse.

If that doesn't solve the problem, can you post your options class as well?

nemec avatar Jan 19 '17 06:01 nemec

I'm trying to figure out the same thing. I'm using v2.1.1-beta. I'm trying to create a program that will support different commands. I'm using ParseArguments and passing in the possible types using the options classes I created.

A simple example is below. When I run this in the debugger I can see that parserResults has a property called Value and it's of type SecondCommandOptions. When typing out the code, there's no Value property on the parserResults object.

How can I get the Value from parserResults so I can get it's type and cast it to the appropriate options class?

using CommandLine;

namespace TestCommandLineArguments
{
    [Verb("firstcommand")]
    internal class FirstCommandOptions
    {
        [Option("setting")]
        public string Setting { get; set; }
    }

    [Verb("secondcommand")]
    internal class SecondCommandOptions
    {
        [Option("setting")]
        public string Setting { get; set; }
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            args = new[] {"secondcommand", "--setting", "value"};

            var parserResults = Parser.Default.ParseArguments(args, typeof(FirstCommandOptions), typeof(SecondCommandOptions));

            if (parserResults.Tag == ParserResultType.Parsed)
            {
                //If I uncomment the following line I get : Cannot resolve symbol 'Value'
                //var value = parserResults.Value;

                //Do something based on what options class was created
            }
        }
    }
}

LtKlaus avatar Mar 10 '17 20:03 LtKlaus

I was able to get Value using Reflection and was able to cast it to my options classes. I'm not sure why the Value property isn't accessible without using Reflection.

            var type = parserResults.GetType();
            var prop = type.GetProperty("Value");
            var value = prop.GetValue(parserResults);

            if (value is FirstCommandOptions)
            {
                var commandOptions = value as FirstCommandOptions;
                //Run my first command
            }

            if (value is SecondCommandOptions)
            {
                var commandOptions = value as SecondCommandOptions;
                //Run my second command
            }

LtKlaus avatar Mar 10 '17 23:03 LtKlaus

Actually Reflection isn't needed and I realized why. I wasn't paying attention to the return value from ParseArguments which is ParserResult< object > and that can cast to Parsed< object > or NotParsed< object >. I just needed to parse it to Parsed< object > then I could access Value and could then check the type of Value and cast it to the appropriate options class.

Hope this will help someone else figure this out quicker than I did. Spent more time scratching my head than I would like to admit.

    ```
    private static void Main(string[] args)
    {
        args = new[] {"secondcommand", "--setting", "value"};

        var parserResults = Parser.Default.ParseArguments(args, typeof(FirstCommandOptions), typeof(SecondCommandOptions));

        if (parserResults.Tag == ParserResultType.Parsed)
        {
            var parsed = parserResults as Parsed<object>;
            var value = parsed.Value;

            //Then figure out the type of "value" and continue on
        }
    }

LtKlaus avatar Mar 10 '17 23:03 LtKlaus

@LtKlaus there are two methods on ParserResult: WithParsed and WithNotParsed. Those do the appropriate conversion for you. It's a bit of a 'functional' way of doing things.

nemec avatar Mar 11 '17 01:03 nemec

@nemec Thanks. I just had a look at those methods and gave them a quick test. They do the conversion for me but with the drawback of not being able to return a value. My current method that processes the Value will return the command that's associated with the options class that was created. I'd have to make a few changes in my code to handle the commands differently but it's do able and worth a look.

LtKlaus avatar Mar 13 '17 15:03 LtKlaus

This new version of the parser is a setback implementing the WithParsedResult And WithNotParsed...

I am rolling back to version 1.9.71.2 stable, where the options class get initialized with the values - easy peasy.

theodorjohannesen avatar Jan 31 '18 18:01 theodorjohannesen

I scratched my head for about 20 minutes on this wondering why it was so difficult to use.

Ended up using this solution, but it is very strange to have to declare a lambda with an external reference just to pass back out. The rest of my app isn't setup to use the functional style

Options options;
Parser.Default.ParseArguments<Options>(args).WithParsed(opts => { options = opts; });

Ideally I'd just like to be able to do something this simple:

var options = Parser.Default.ParseArguments<Options>(args);

simonmurdock avatar Jul 17 '18 14:07 simonmurdock