diff --git a/ICD.Common.Utils.Tests/Extensions/TypeExtensionsTest.cs b/ICD.Common.Utils.Tests/Extensions/TypeExtensionsTest.cs index 064d007..226bee3 100644 --- a/ICD.Common.Utils.Tests/Extensions/TypeExtensionsTest.cs +++ b/ICD.Common.Utils.Tests/Extensions/TypeExtensionsTest.cs @@ -155,6 +155,15 @@ namespace ICD.Common.Utils.Tests.Extensions Assert.AreEqual(expected, type.GetNameWithoutGenericArity()); } + [TestCase(typeof(int), "System.Int32")] + [TestCase(typeof(int?), "System.Nullable`1[[System.Int32]]")] + [TestCase(typeof(KeyValuePair), "System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]")] + [TestCase(typeof(List<>), "System.Collections.Generic.List`1")] + public void GetMinimalNameTest(Type type, string expected) + { + Assert.AreEqual(expected, type.GetMinimalName()); + } + [TestCase(typeof(int), "System.Int32, System.Private.CoreLib")] [TestCase(typeof(int?), "System.Nullable`1[[System.Int32, System.Private.CoreLib]], System.Private.CoreLib")] public void GetNameWithoutAssemblyDetailsTest(Type type, string expected) diff --git a/ICD.Common.Utils/Extensions/JsonWriterExtensions.cs b/ICD.Common.Utils/Extensions/JsonWriterExtensions.cs index 8580eb7..c37e260 100644 --- a/ICD.Common.Utils/Extensions/JsonWriterExtensions.cs +++ b/ICD.Common.Utils/Extensions/JsonWriterExtensions.cs @@ -7,16 +7,6 @@ namespace ICD.Common.Utils.Extensions { public static class JsonWriterExtensions { - private static readonly Dictionary s_TypeToString; - - /// - /// Static constructor. - /// - static JsonWriterExtensions() - { - s_TypeToString = new Dictionary(); - } - /// /// Writes the type value. /// @@ -34,23 +24,7 @@ namespace ICD.Common.Utils.Extensions return; } - string name; - if (!s_TypeToString.TryGetValue(type, out name)) - { - // We'll use the full name if it can be deserialized. - // Full name ends up longer than name without assembly details when - // using nullables, so we do a length check to get the smallest possible - // string representation for the type. - string fullName = Type.GetType(type.FullName) == null ? null : type.FullName; - string nameWithoutAssembly = type.GetNameWithoutAssemblyDetails(); - - name = fullName == null || fullName.Length > nameWithoutAssembly.Length - ? nameWithoutAssembly - : fullName; - - s_TypeToString.Add(type, name); - } - + string name = type.GetMinimalName(); extends.WriteValue(name); } diff --git a/ICD.Common.Utils/Extensions/TypeExtensions.cs b/ICD.Common.Utils/Extensions/TypeExtensions.cs index dc5f471..eaa3cca 100644 --- a/ICD.Common.Utils/Extensions/TypeExtensions.cs +++ b/ICD.Common.Utils/Extensions/TypeExtensions.cs @@ -62,6 +62,7 @@ namespace ICD.Common.Utils.Extensions private static readonly Dictionary s_TypeBaseTypes; private static readonly Dictionary s_TypeImmediateInterfaces; private static readonly Dictionary s_TypeMinimalInterfaces; + private static readonly Dictionary s_TypeToMinimalName; private static readonly Dictionary s_TypeToNameWithoutAssemblyDetails; /// @@ -73,6 +74,7 @@ namespace ICD.Common.Utils.Extensions s_TypeBaseTypes = new Dictionary(); s_TypeImmediateInterfaces = new Dictionary(); s_TypeMinimalInterfaces = new Dictionary(); + s_TypeToMinimalName = new Dictionary(); s_TypeToNameWithoutAssemblyDetails = new Dictionary(); } @@ -309,6 +311,57 @@ namespace ICD.Common.Utils.Extensions return index == -1 ? name : name.Substring(0, index); } + /// + /// Gets the smallest possible string representation for the given type that + /// can be converted back to a Type via Type.GetType(string). + /// + /// + /// + public static string GetMinimalName(this Type extends) + { + if (extends == null) + throw new ArgumentNullException("extends"); + + string name; + if (!s_TypeToMinimalName.TryGetValue(extends, out name)) + { + // Generics are a pain + if (extends.IsGenericType) + { + string nameWithoutAssemblyDetails = Type.GetType(extends.FullName) == null + ? extends.GetNameWithoutAssemblyDetails() + : extends.FullName; + int genericStart = nameWithoutAssemblyDetails.IndexOf('['); + if (genericStart < 0) + { + name = nameWithoutAssemblyDetails; + } + else + { + string genericParameterNames = + string.Join("],[", extends.GetGenericArguments().Select(t => t.GetMinimalName()).ToArray()); + int genericEnd = nameWithoutAssemblyDetails.LastIndexOf(']'); + + name = new StringBuilder().Append(nameWithoutAssemblyDetails, 0, genericStart + 2) + .Append(genericParameterNames) + .Append(nameWithoutAssemblyDetails, genericEnd - 1, + nameWithoutAssemblyDetails.Length - genericEnd + 1) + .ToString(); + } + } + else + { + name = Type.GetType(extends.FullName) == null + ? extends.GetNameWithoutAssemblyDetails() + : extends.FullName; + } + + s_TypeToMinimalName.Add(extends, name); + } + + return name; + } + /// /// Gets the string representation for the type. ///