Skip to content

Commit 5de17a7

Browse files
committed
Eliminate allocations from ReflectionUtility.GetImplementedInterfaces
1 parent 07edda0 commit 5de17a7

File tree

7 files changed

+30
-61
lines changed

7 files changed

+30
-61
lines changed

YamlDotNet/ReflectionExtensions.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,29 @@ public static bool IsGenericTypeDefinition(this Type type)
4949
return type.GetTypeInfo().IsGenericTypeDefinition;
5050
}
5151

52+
public static Type? GetImplementationOfOpenGenericInterface(this Type type, Type openGenericType)
53+
{
54+
if (!openGenericType.IsGenericType || !openGenericType.IsInterface)
55+
{
56+
// Note we can likely relax this constraint to also allow for matching other types
57+
throw new ArgumentException("The type must be a generic type definition and an interface", nameof(openGenericType));
58+
}
59+
60+
// First check if the type itself is the open generic type
61+
if (IsGenericDefinitionOfType(type, openGenericType))
62+
{
63+
return type;
64+
}
65+
66+
// Then check the interfaces
67+
return type.FindInterfaces(static (t, context) => IsGenericDefinitionOfType(t, context), openGenericType).FirstOrDefault();
68+
69+
static bool IsGenericDefinitionOfType(Type t, object? context)
70+
{
71+
return t.IsGenericType && t.GetGenericTypeDefinition() == (Type)context;
72+
}
73+
}
74+
5275
public static bool IsInterface(this Type type)
5376
{
5477
return type.GetTypeInfo().IsInterface;

YamlDotNet/Serialization/NodeDeserializers/CollectionNodeDeserializer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public bool Deserialize(IParser parser, Type expectedType, Func<IParser, Type, o
4747
IList? list;
4848
var canUpdate = true;
4949
Type itemType;
50-
var genericCollectionType = ReflectionUtility.GetImplementedGenericInterface(expectedType, typeof(ICollection<>));
50+
var genericCollectionType = expectedType.GetImplementationOfOpenGenericInterface((typeof(ICollection<>)));
5151
if (genericCollectionType != null)
5252
{
5353
var genericArguments = genericCollectionType.GetGenericArguments();
@@ -58,7 +58,7 @@ public bool Deserialize(IParser parser, Type expectedType, Func<IParser, Type, o
5858
if (list == null)
5959
{
6060
// Uncommon case where a type implements IList<T> but not IList
61-
var genericListType = ReflectionUtility.GetImplementedGenericInterface(expectedType, typeof(IList<>));
61+
var genericListType = expectedType.GetImplementationOfOpenGenericInterface(typeof(IList<>));
6262
canUpdate = genericListType != null;
6363
list = (IList?)Activator.CreateInstance(typeof(GenericCollectionToNonGenericAdapter<>).MakeGenericType(itemType), value);
6464
}

YamlDotNet/Serialization/NodeDeserializers/DictionaryNodeDeserializer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public bool Deserialize(IParser parser, Type expectedType, Func<IParser, Type, o
4343
{
4444
IDictionary? dictionary;
4545
Type keyType, valueType;
46-
var genericDictionaryType = ReflectionUtility.GetImplementedGenericInterface(expectedType, typeof(IDictionary<,>));
46+
var genericDictionaryType = expectedType.GetImplementationOfOpenGenericInterface(typeof(IDictionary<,>));
4747
if (genericDictionaryType != null)
4848
{
4949
var genericArguments = genericDictionaryType.GetGenericArguments();

YamlDotNet/Serialization/NodeDeserializers/EnumerableNodeDeserializer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public bool Deserialize(IParser parser, Type expectedType, Func<IParser, Type, o
3838
}
3939
else
4040
{
41-
var iEnumerable = ReflectionUtility.GetImplementedGenericInterface(expectedType, typeof(IEnumerable<>));
41+
var iEnumerable = expectedType.GetImplementationOfOpenGenericInterface(typeof(IEnumerable<>));
4242
if (iEnumerable != expectedType)
4343
{
4444
value = null;

YamlDotNet/Serialization/ObjectFactories/ObjectFactoryBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public virtual void ExecuteOnSerializing(object value)
5555

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

7171
public virtual Type GetValueType(Type type)
7272
{
73-
var enumerableType = ReflectionUtility.GetImplementedGenericInterface(type, typeof(IEnumerable<>));
73+
var enumerableType = type.GetImplementationOfOpenGenericInterface(typeof(IEnumerable<>));
7474
var itemType = enumerableType != null ? enumerableType.GetGenericArguments()[0] : typeof(object);
7575
return itemType;
7676
}

YamlDotNet/Serialization/Utilities/ReflectionUtility.cs

Lines changed: 0 additions & 54 deletions
This file was deleted.

YamlDotNet/YamlDotNet.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
1818
<WarningsAsErrors>true</WarningsAsErrors>
1919

20-
<LangVersion>8.0</LangVersion>
20+
<LangVersion>9.0</LangVersion>
2121
<Nullable>enable</Nullable>
2222

2323
<NetStandard>false</NetStandard>

0 commit comments

Comments
 (0)