-
-
Notifications
You must be signed in to change notification settings - Fork 82
/
Copy pathFastActivator.cs
61 lines (53 loc) · 2.29 KB
/
FastActivator.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
namespace Schema.NET;
using System;
using System.Collections.Concurrent;
using System.Linq.Expressions;
using System.Reflection;
/// <summary>
/// A faster version of <see cref="Activator.CreateInstance(Type, object[])"/> by providing constructor delegates.
/// </summary>
internal static class FastActivator
{
private static readonly ConcurrentDictionary<(Type, Type), Delegate> ConstructorDelegateLookup = new();
/// <summary>
/// Creates a constructor delegate for the specified type.
/// </summary>
/// <typeparam name="T1">Type of first argument for constructor.</typeparam>
/// <param name="objectType">The object to find the constructor.</param>
/// <returns>The constructor delegate.</returns>
public static Func<T1, object>? GetDynamicConstructor<T1>(Type objectType)
{
var constructorKey = (objectType, typeof(T1));
if (!ConstructorDelegateLookup.TryGetValue(constructorKey, out var constructorDelegate))
{
var constructor = GetConstructorInfo(objectType, typeof(T1));
if (constructor is not null)
{
constructorDelegate = CreateConstructorDelegate<T1>(constructor);
ConstructorDelegateLookup.TryAdd(constructorKey, constructorDelegate);
}
}
return constructorDelegate as Func<T1, object>;
}
private static Func<T1, object> CreateConstructorDelegate<T1>(ConstructorInfo constructor) => Expression.Lambda<Func<T1, object>>(
Expression.Convert(
Expression.New(constructor, ConstructorParameter<T1>.SingleParameter),
typeof(object)),
ConstructorParameter<T1>.SingleParameter).Compile();
private static ConstructorInfo? GetConstructorInfo(Type objectType, Type parameter1)
{
foreach (var constructor in objectType.GetTypeInfo().DeclaredConstructors)
{
var parameters = constructor.GetParameters();
if (constructor.IsPublic && parameters.Length == 1 && parameters[0].ParameterType == parameter1)
{
return constructor;
}
}
return null;
}
private static class ConstructorParameter<T1>
{
public static readonly ParameterExpression[] SingleParameter = new[] { Expression.Parameter(typeof(T1)) };
}
}