diff --git a/src/CommandLine/Core/ReflectionExtensions.cs b/src/CommandLine/Core/ReflectionExtensions.cs index 9b6f858c..72e162b5 100644 --- a/src/CommandLine/Core/ReflectionExtensions.cs +++ b/src/CommandLine/Core/ReflectionExtensions.cs @@ -209,5 +209,13 @@ public static bool IsPrimitiveEx(this Type type) }.Contains(type) || Convert.GetTypeCode(type) != TypeCode.Object; } + + public static bool IsCustomStruct(this Type type) + { + var isStruct = type.GetTypeInfo().IsValueType && !type.GetTypeInfo().IsPrimitive && !type.GetTypeInfo().IsEnum && type != typeof(Guid); + if (!isStruct) return false; + var ctor = type.GetTypeInfo().GetConstructor(new[] { typeof(string) }); + return ctor != null; + } } } diff --git a/src/CommandLine/Core/TypeConverter.cs b/src/CommandLine/Core/TypeConverter.cs index fef7945a..354c4316 100644 --- a/src/CommandLine/Core/TypeConverter.cs +++ b/src/CommandLine/Core/TypeConverter.cs @@ -111,6 +111,7 @@ private static Result ChangeTypeScalarImpl(string value, Type } }; + if (conversionType.IsCustomStruct()) return Result.Try(makeType); return Result.Try( conversionType.IsPrimitiveEx() || ReflectionHelper.IsFSharpOptionType(conversionType) ? changeType @@ -135,4 +136,4 @@ private static object ToEnum(this string value, Type conversionType, bool ignore throw new FormatException(); } } -} \ No newline at end of file +} diff --git a/tests/CommandLine.Tests/Fakes/Custom_Struct.cs b/tests/CommandLine.Tests/Fakes/Custom_Struct.cs new file mode 100644 index 00000000..64807f6b --- /dev/null +++ b/tests/CommandLine.Tests/Fakes/Custom_Struct.cs @@ -0,0 +1,56 @@ +// Copyright 2005-2015 Giacomo Stelluti Scala & Contributors. All rights reserved. See License.md in the project root for license information. + +using System; + +namespace CommandLine.Tests.Fakes +{ + public class CustomStructOptions + { + [Option('c', "custom", HelpText = "Custom Type")] + public CustomStruct Custom { get; set; } + } + + public struct CustomStruct + { + public string Input { get; set; } + public string Server { get; set; } + public int Port { get; set; } + public CustomStruct(string url) + { + Input = url; + Server = ""; + Port = 80; + var data = url.Split(':'); + if (data.Length == 2) + { + Server = data[0]; + Port = Convert.ToInt32(data[1]); + } + } + } + + public class CustomClassOptions + { + [Option('c', "custom", HelpText = "Custom Type")] + public CustomClass Custom { get; set; } + } + + public class CustomClass + { + public string Input { get; set; } + public string Server { get; set; } + public int Port { get; set; } + public CustomClass(string url) + { + Input = url; + Server = ""; + Port = 80; + var data = url.Split(':'); + if (data.Length == 2) + { + Server = data[0]; + Port = Convert.ToInt32(data[1]); + } + } + } +} diff --git a/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs b/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs index 643878fd..a74a1af0 100644 --- a/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs +++ b/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs @@ -1221,6 +1221,42 @@ public void Options_In_Group_Do_Not_Allow_Mutually_Exclusive_Set() errors.Should().BeEquivalentTo(expectedResult); } + #region custom types + + + [Theory] + [InlineData(new[] { "-c", "localhost:8080" }, "localhost", 8080)] + public void Parse_custom_struct_type(string[] arguments, string expectedServer, int expectedPort) + { + //Arrange + + // Act + var result = InvokeBuild(arguments); + + // Assert + var customValue = ((Parsed)result).Value.Custom; + customValue.Server.Should().Be(expectedServer); + customValue.Port.Should().Be(expectedPort); + customValue.Input.Should().Be(arguments[1]); + } + + [Theory] + [InlineData(new[] { "-c", "localhost:8080" }, "localhost", 8080)] + public void Parse_custom_class_type(string[] arguments, string expectedServer, int expectedPort) + { + //Arrange + + // Act + var result = InvokeBuild(arguments); + + // Assert + var customValue = ((Parsed)result).Value.Custom; + customValue.Server.Should().Be(expectedServer); + customValue.Port.Should().Be(expectedPort); + customValue.Input.Should().Be(arguments[1]); + } + + #endregion private class ValueWithNoSetterOptions { [Value(0, MetaName = "Test", Default = 0)]