diff --git a/src/Vertical/CommandLine/Conversion/ConversionException.cs b/src/Vertical/CommandLine/Conversion/ConversionException.cs index b53fabe..5766f7f 100644 --- a/src/Vertical/CommandLine/Conversion/ConversionException.cs +++ b/src/Vertical/CommandLine/Conversion/ConversionException.cs @@ -48,7 +48,9 @@ internal ConversionException(string context, Type targetType, string argumentVal // Formats the exception message. private static string FormatMessage(string context, Type targetType, string argumentValue) { - return $"{context}: could not convert {Formatting.Quote(argumentValue)} to target type {targetType.Name}."; + var friendlyTargetType = TypeHelpers.GetFriendlyDisplayName(targetType); + + return $"{context}: could not convert {Formatting.Quote(argumentValue)} to target type {friendlyTargetType}."; } } } \ No newline at end of file diff --git a/src/Vertical/CommandLine/Infrastructure/TypeHelpers.cs b/src/Vertical/CommandLine/Infrastructure/TypeHelpers.cs index bdced5a..421f82b 100644 --- a/src/Vertical/CommandLine/Infrastructure/TypeHelpers.cs +++ b/src/Vertical/CommandLine/Infrastructure/TypeHelpers.cs @@ -101,5 +101,28 @@ internal static string GetGenericTypeName(string typeName) var markerIndex = typeName.IndexOf('`'); return markerIndex > -1 ? typeName.Substring(0, markerIndex) : typeName; } + + internal static string GetFriendlyDisplayName(Type type) + { + try + { + if (!type.IsGenericType) + return type.Name; + + var genericTypeName = type.GetGenericTypeDefinition().Name; + var tickIndex = genericTypeName.IndexOf('`'); + var trimmedTypeName = genericTypeName.Substring(0, tickIndex); + var typeParams = type + .GetGenericArguments() + .Select(GetFriendlyDisplayName); + var typeParamString = string.Join(",", typeParams); + + return $"{trimmedTypeName}<{typeParamString}>"; + } + catch + { + return type.Name; + } + } } } \ No newline at end of file diff --git a/test/Infrastructure/TypeHelpersTests.cs b/test/Infrastructure/TypeHelpersTests.cs index d128079..808beb2 100644 --- a/test/Infrastructure/TypeHelpersTests.cs +++ b/test/Infrastructure/TypeHelpersTests.cs @@ -5,6 +5,7 @@ // or refer to https://opensource.org/licenses/MIT using System; +using System.Collections.Generic; using Shouldly; using Vertical.CommandLine.Infrastructure; using Xunit; @@ -20,5 +21,15 @@ public void GetKnownMethodInfoThrowsForInvalidMethod() Array.Empty(), typeof(void))); } + + [Theory] + [InlineData(typeof(string), "String")] + [InlineData(typeof(int), "Int32")] + [InlineData(typeof(int?), "Nullable")] + [InlineData(typeof(Dictionary), "Dictionary,String>")] + public void GetFriendlyNameReturnsExpected(Type type, string expected) + { + TypeHelpers.GetFriendlyDisplayName(type).ShouldBe(expected); + } } } \ No newline at end of file