mirror of
https://github.com/ICDSystems/ICD.Common.Utils.git
synced 2026-02-16 13:15:07 +00:00
perf: Better JSON serialization of nullable types
This commit is contained in:
@@ -155,6 +155,15 @@ namespace ICD.Common.Utils.Tests.Extensions
|
|||||||
Assert.AreEqual(expected, type.GetNameWithoutGenericArity());
|
Assert.AreEqual(expected, type.GetNameWithoutGenericArity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCase(typeof(int), "System.Int32")]
|
||||||
|
[TestCase(typeof(int?), "System.Nullable`1[[System.Int32]]")]
|
||||||
|
[TestCase(typeof(KeyValuePair<int, string>), "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.Int32, System.Private.CoreLib")]
|
||||||
[TestCase(typeof(int?), "System.Nullable`1[[System.Int32, System.Private.CoreLib]], System.Private.CoreLib")]
|
[TestCase(typeof(int?), "System.Nullable`1[[System.Int32, System.Private.CoreLib]], System.Private.CoreLib")]
|
||||||
public void GetNameWithoutAssemblyDetailsTest(Type type, string expected)
|
public void GetNameWithoutAssemblyDetailsTest(Type type, string expected)
|
||||||
|
|||||||
@@ -7,16 +7,6 @@ namespace ICD.Common.Utils.Extensions
|
|||||||
{
|
{
|
||||||
public static class JsonWriterExtensions
|
public static class JsonWriterExtensions
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<Type, string> s_TypeToString;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Static constructor.
|
|
||||||
/// </summary>
|
|
||||||
static JsonWriterExtensions()
|
|
||||||
{
|
|
||||||
s_TypeToString = new Dictionary<Type, string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes the type value.
|
/// Writes the type value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -34,23 +24,7 @@ namespace ICD.Common.Utils.Extensions
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string name;
|
string name = type.GetMinimalName();
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
extends.WriteValue(name);
|
extends.WriteValue(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ namespace ICD.Common.Utils.Extensions
|
|||||||
private static readonly Dictionary<Type, Type[]> s_TypeBaseTypes;
|
private static readonly Dictionary<Type, Type[]> s_TypeBaseTypes;
|
||||||
private static readonly Dictionary<Type, Type[]> s_TypeImmediateInterfaces;
|
private static readonly Dictionary<Type, Type[]> s_TypeImmediateInterfaces;
|
||||||
private static readonly Dictionary<Type, Type[]> s_TypeMinimalInterfaces;
|
private static readonly Dictionary<Type, Type[]> s_TypeMinimalInterfaces;
|
||||||
|
private static readonly Dictionary<Type, string> s_TypeToMinimalName;
|
||||||
private static readonly Dictionary<Type, string> s_TypeToNameWithoutAssemblyDetails;
|
private static readonly Dictionary<Type, string> s_TypeToNameWithoutAssemblyDetails;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -73,6 +74,7 @@ namespace ICD.Common.Utils.Extensions
|
|||||||
s_TypeBaseTypes = new Dictionary<Type, Type[]>();
|
s_TypeBaseTypes = new Dictionary<Type, Type[]>();
|
||||||
s_TypeImmediateInterfaces = new Dictionary<Type, Type[]>();
|
s_TypeImmediateInterfaces = new Dictionary<Type, Type[]>();
|
||||||
s_TypeMinimalInterfaces = new Dictionary<Type, Type[]>();
|
s_TypeMinimalInterfaces = new Dictionary<Type, Type[]>();
|
||||||
|
s_TypeToMinimalName = new Dictionary<Type, string>();
|
||||||
s_TypeToNameWithoutAssemblyDetails = new Dictionary<Type, string>();
|
s_TypeToNameWithoutAssemblyDetails = new Dictionary<Type, string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,6 +311,57 @@ namespace ICD.Common.Utils.Extensions
|
|||||||
return index == -1 ? name : name.Substring(0, index);
|
return index == -1 ? name : name.Substring(0, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the smallest possible string representation for the given type that
|
||||||
|
/// can be converted back to a Type via Type.GetType(string).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="extends"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the string representation for the type.
|
/// Gets the string representation for the type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user