natemcmaster/CommandLineUtils

System.InvalidOperationException: on parsing GUID command line option.

AlexeyEvlampiev opened this issue · 3 comments

Describe the bug
System.InvalidOperationException: Could not automatically determine how to convert string values into System.Guid is thrown when registering Guid- command line options.

To Reproduce
Steps to reproduce the behavior:

  1. Using this version of the library '2.5.0'
  2. Run this code
namespace ConsoleApp1
{
    using System;
    using System.Diagnostics;
    using McMaster.Extensions.CommandLineUtils;

    class Program
    {
        static void Main(string[] args)
        {
            var cmd = new CommandLineApplication();
            var guidOption = cmd
                .Option<Guid>("-g", "A GUID-option", CommandOptionType.SingleValue)
                .IsRequired();

            var expected = Guid.NewGuid().ToString();
            cmd.OnExecute(() =>
            {
                var actual = guidOption.ParsedValue;
                Debug.Assert(expected == actual.ToString());
            });
            cmd.Execute(new []{"-g", expected });
        }
    }
}
  1. See error "Could not automatically determine how to convert string values into System.Guid"

Expected behavior
Specifying command options of the Guid type should work seamlessly.

Additional context
I would suggest introducing a generic value parser that would cover most of the CLR standard library types:

using System;
    using System.ComponentModel;
    using System.Globalization;
    using McMaster.Extensions.CommandLineUtils.Abstractions;

    public class GenericValueParser : IValueParser {
        private GenericValueParser(Type targetType, TypeConverter converter)
        {
            TargetType = targetType;
            Converter = converter;
        }

        public static GenericValueParser Get<T>()
        {
            var targetType = typeof(T); 
            var converter = TypeDescriptor.GetConverter(targetType);
            return converter.CanConvertFrom(typeof(string)) ? new GenericValueParser(targetType, converter) : null;
        }

        public Type TargetType { get; }
        public TypeConverter Converter { get; }

        public object Parse(string argName, string value, CultureInfo culture)
        {
            return Converter.ConvertFromString(null, culture, value);
        }

    }

The originally failing code would be fixed with e.g.

namespace ConsoleApp1
{
    using System;
    using System.Diagnostics;
    using McMaster.Extensions.CommandLineUtils;

    class Program
    {
        static void Main(string[] args)
        {
            var cmd = new CommandLineApplication();
            cmd.ValueParsers.Add(GenericValueParser.Get<Guid>());
            var guidOption = cmd
                .Option<Guid>("-g", "A GUID-option", CommandOptionType.SingleValue)
                .IsRequired();

            var expected = Guid.NewGuid().ToString();
            cmd.OnExecute(() =>
            {
                var actual = guidOption.ParsedValue;
                Debug.Assert(expected == actual.ToString());
            });
            cmd.Execute(new []{"-g", expected });
        }
    }
}

Would you be willing to send a pull request to fix this? Seems like you have posted most of the solution already 😄

To be honest I have no experience in contributing to open source. If my PR is done not the right way, could someone help by picking up the change I made?

Congrats on your first PR! Yes, you did it correctly (kudos to you). I'll leave some comments on your PR, #345.