-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
DelegateFactory.cs
99 lines (82 loc) · 3.69 KB
/
DelegateFactory.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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using AutoMapper.Configuration;
using AutoMapper.Mappers.Internal;
namespace AutoMapper.Execution
{
using static Expression;
using static Internal.ExpressionFactory;
using static ElementTypeHelper;
public static class DelegateFactory
{
private static readonly LockingConcurrentDictionary<Type, Func<object>> CtorCache = new LockingConcurrentDictionary<Type, Func<object>>(GenerateConstructor);
public static Func<object> CreateCtor(Type type) => CtorCache.GetOrAdd(type);
private static Func<object> GenerateConstructor(Type type)
{
var ctorExpr = GenerateConstructorExpression(type);
return Lambda<Func<object>>(Convert(ctorExpr, typeof(object))).Compile();
}
public static Expression GenerateConstructorExpression(Type type, ProfileMap configuration) =>
configuration.AllowNullDestinationValues
? GenerateConstructorExpression(type)
: GenerateNonNullConstructorExpression(type);
public static Expression GenerateNonNullConstructorExpression(Type type) => type.IsValueType()
? Default(type)
: (type == typeof(string)
? Constant(string.Empty)
: GenerateConstructorExpression(type)
);
public static Expression GenerateConstructorExpression(Type type)
{
if (type.IsValueType())
{
return Default(type);
}
if (type == typeof(string))
{
return Constant(null, typeof(string));
}
if (type.IsInterface())
{
return type.ImplementsGenericInterface(typeof(IDictionary<,>))
? CreateCollection(type, typeof(Dictionary<,>))
: (type.ImplementsGenericInterface(typeof(ICollection<>))
? CreateCollection(type, typeof(List<>))
: InvalidType(type, $"Cannot create an instance of interface type {type}."));
}
if (type.IsAbstract())
{
return InvalidType(type, $"Cannot create an instance of abstract type {type}.");
}
var constructors = type
.GetDeclaredConstructors()
.Where(ci => !ci.IsStatic);
//find a ctor with only optional args
var ctorWithOptionalArgs = constructors.FirstOrDefault(c => c.GetParameters().All(p => p.IsOptional));
if (ctorWithOptionalArgs == null)
{
return InvalidType(type, $"{type} needs to have a constructor with 0 args or only optional args.");
}
//get all optional default values
var args = ctorWithOptionalArgs
.GetParameters()
.Select(p => Constant(p.GetDefaultValue(), p.ParameterType)).ToArray();
//create the ctor expression
return New(ctorWithOptionalArgs, args);
}
private static Expression CreateCollection(Type type, Type collectionType)
{
var listType = collectionType.MakeGenericType(GetElementTypes(type, ElementTypeFlags.BreakKeyValuePair));
if (type.IsAssignableFrom(listType))
return ToType(New(listType), type);
return InvalidType(type, $"Cannot create an instance of interface type {type}.");
}
private static Expression InvalidType(Type type, string message)
{
var ex = new ArgumentException(message, "type");
return Block(Throw(Constant(ex)), Constant(null, type));
}
}
}