Skip to content

Commit

Permalink
Merge pull request #955 from MattKotsenas/refactor/reflection-interfa…
Browse files Browse the repository at this point in the history
…ces-allocs

Eliminate allocations from ReflectionUtility.GetImplementedInterfaces
  • Loading branch information
EdwardCooke authored Sep 1, 2024
2 parents 462c5a0 + d49e964 commit de005eb
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 60 deletions.
23 changes: 23 additions & 0 deletions YamlDotNet/ReflectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,29 @@ public static bool IsGenericTypeDefinition(this Type type)
return type.GetTypeInfo().IsGenericTypeDefinition;
}

public static Type? GetImplementationOfOpenGenericInterface(this Type type, Type openGenericType)
{
if (!openGenericType.IsGenericType || !openGenericType.IsInterface)
{
// Note we can likely relax this constraint to also allow for matching other types
throw new ArgumentException("The type must be a generic type definition and an interface", nameof(openGenericType));
}

// First check if the type itself is the open generic type
if (IsGenericDefinitionOfType(type, openGenericType))
{
return type;
}

// Then check the interfaces
return type.FindInterfaces(static (t, context) => IsGenericDefinitionOfType(t, context), openGenericType).FirstOrDefault();

static bool IsGenericDefinitionOfType(Type t, object? context)
{
return t.IsGenericType && t.GetGenericTypeDefinition() == (Type)context;
}
}

public static bool IsInterface(this Type type)
{
return type.GetTypeInfo().IsInterface;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public bool Deserialize(IParser parser, Type expectedType, Func<IParser, Type, o
IList? list;
var canUpdate = true;
Type itemType;
var genericCollectionType = ReflectionUtility.GetImplementedGenericInterface(expectedType, typeof(ICollection<>));
var genericCollectionType = expectedType.GetImplementationOfOpenGenericInterface((typeof(ICollection<>)));
if (genericCollectionType != null)
{
var genericArguments = genericCollectionType.GetGenericArguments();
Expand All @@ -58,7 +58,7 @@ public bool Deserialize(IParser parser, Type expectedType, Func<IParser, Type, o
if (list == null)
{
// Uncommon case where a type implements IList<T> but not IList
var genericListType = ReflectionUtility.GetImplementedGenericInterface(expectedType, typeof(IList<>));
var genericListType = expectedType.GetImplementationOfOpenGenericInterface(typeof(IList<>));
canUpdate = genericListType != null;
list = (IList?)Activator.CreateInstance(typeof(GenericCollectionToNonGenericAdapter<>).MakeGenericType(itemType), value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public bool Deserialize(IParser parser, Type expectedType, Func<IParser, Type, o
{
IDictionary? dictionary;
Type keyType, valueType;
var genericDictionaryType = ReflectionUtility.GetImplementedGenericInterface(expectedType, typeof(IDictionary<,>));
var genericDictionaryType = expectedType.GetImplementationOfOpenGenericInterface(typeof(IDictionary<,>));
if (genericDictionaryType != null)
{
var genericArguments = genericDictionaryType.GetGenericArguments();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public bool Deserialize(IParser parser, Type expectedType, Func<IParser, Type, o
}
else
{
var iEnumerable = ReflectionUtility.GetImplementedGenericInterface(expectedType, typeof(IEnumerable<>));
var iEnumerable = expectedType.GetImplementationOfOpenGenericInterface(typeof(IEnumerable<>));
if (iEnumerable != expectedType)
{
value = null;
Expand Down
4 changes: 2 additions & 2 deletions YamlDotNet/Serialization/ObjectFactories/ObjectFactoryBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public virtual void ExecuteOnSerializing(object value)

public virtual bool GetDictionary(IObjectDescriptor descriptor, out IDictionary? dictionary, out Type[]? genericArguments)
{
var genericDictionaryType = ReflectionUtility.GetImplementedGenericInterface(descriptor.Type, typeof(IDictionary<,>));
var genericDictionaryType = descriptor.Type.GetImplementationOfOpenGenericInterface(typeof(IDictionary<,>));
if (genericDictionaryType != null)
{
genericArguments = genericDictionaryType.GetGenericArguments();
Expand All @@ -70,7 +70,7 @@ public virtual bool GetDictionary(IObjectDescriptor descriptor, out IDictionary?

public virtual Type GetValueType(Type type)
{
var enumerableType = ReflectionUtility.GetImplementedGenericInterface(type, typeof(IEnumerable<>));
var enumerableType = type.GetImplementationOfOpenGenericInterface(typeof(IEnumerable<>));
var itemType = enumerableType != null ? enumerableType.GetGenericArguments()[0] : typeof(object);
return itemType;
}
Expand Down
54 changes: 0 additions & 54 deletions YamlDotNet/Serialization/Utilities/ReflectionUtility.cs

This file was deleted.

0 comments on commit de005eb

Please sign in to comment.