24
24
// OTHER DEALINGS IN THE SOFTWARE.
25
25
26
26
using System ;
27
+ using System . Collections . Concurrent ;
27
28
using System . Collections . Generic ;
28
29
using System . Linq ;
29
30
using System . Reflection ;
30
31
using Autofac . Util ;
31
32
32
33
namespace Autofac . Core . Activators . Reflection
33
34
{
34
- internal class AutowiringPropertyInjector
35
+ internal static class AutowiringPropertyInjector
35
36
{
36
37
public const string InstanceTypeNamedParameter = "Autofac.AutowiringPropertyInjector.InstanceType" ;
37
38
39
+ private static readonly ConcurrentDictionary < PropertyInfo , Action < object , object > > PropertySetters =
40
+ new ConcurrentDictionary < PropertyInfo , Action < object , object > > ( ) ;
41
+
42
+ private static readonly ConcurrentDictionary < Type , PropertyInfo [ ] > InjectableProperties =
43
+ new ConcurrentDictionary < Type , PropertyInfo [ ] > ( ) ;
44
+
45
+ private static readonly MethodInfo CallPropertySetterOpenGenericMethod =
46
+ typeof ( AutowiringPropertyInjector ) . GetTypeInfo ( ) . GetDeclaredMethod ( nameof ( CallPropertySetter ) ) ;
47
+
38
48
public static void InjectProperties ( IComponentContext context , object instance , IPropertySelector propertySelector , IEnumerable < Parameter > parameters )
39
49
{
40
50
if ( context == null )
@@ -57,56 +67,92 @@ public static void InjectProperties(IComponentContext context, object instance,
57
67
throw new ArgumentNullException ( nameof ( parameters ) ) ;
58
68
}
59
69
70
+ var resolveParameters = parameters as Parameter [ ] ?? parameters . ToArray ( ) ;
71
+
60
72
var instanceType = instance . GetType ( ) ;
73
+ var injectableProperties = InjectableProperties . GetOrAdd ( instanceType , type => GetInjectableProperties ( type ) . ToArray ( ) ) ;
61
74
62
- foreach ( var property in instanceType
63
- . GetRuntimeProperties ( )
64
- . Where ( pi => pi . CanWrite ) )
75
+ for ( var index = 0 ; index < injectableProperties . Length ; index ++ )
65
76
{
66
- var propertyType = property . PropertyType ;
77
+ var property = injectableProperties [ index ] ;
67
78
68
- if ( propertyType . GetTypeInfo ( ) . IsValueType && ! propertyType . GetTypeInfo ( ) . IsEnum )
79
+ if ( ! propertySelector . InjectProperty ( property , instance ) )
69
80
{
70
81
continue ;
71
82
}
72
83
73
- if ( propertyType . IsArray && propertyType . GetElementType ( ) . GetTypeInfo ( ) . IsValueType )
84
+ var setParameter = property . SetMethod . GetParameters ( ) [ 0 ] ;
85
+ var valueProvider = ( Func < object > ) null ;
86
+ var parameter = resolveParameters . FirstOrDefault ( p => p . CanSupplyValue ( setParameter , context , out valueProvider ) ) ;
87
+ if ( parameter != null )
74
88
{
89
+ var setter = PropertySetters . GetOrAdd ( property , MakeFastPropertySetter ) ;
90
+ setter ( instance , valueProvider ( ) ) ;
75
91
continue ;
76
92
}
77
93
78
- if ( propertyType . IsGenericEnumerableInterfaceType ( ) && propertyType . GetTypeInfo ( ) . GenericTypeArguments [ 0 ] . GetTypeInfo ( ) . IsValueType )
94
+ var propertyService = new TypedService ( property . PropertyType ) ;
95
+ var instanceTypeParameter = new NamedParameter ( InstanceTypeNamedParameter , instanceType ) ;
96
+ if ( context . TryResolveService ( propertyService , new Parameter [ ] { instanceTypeParameter } , out var propertyValue ) )
97
+ {
98
+ var setter = PropertySetters . GetOrAdd ( property , MakeFastPropertySetter ) ;
99
+ setter ( instance , propertyValue ) ;
100
+ }
101
+ }
102
+ }
103
+
104
+ private static IEnumerable < PropertyInfo > GetInjectableProperties ( Type instanceType )
105
+ {
106
+ foreach ( var property in instanceType . GetRuntimeProperties ( ) )
107
+ {
108
+ if ( ! property . CanWrite )
79
109
{
80
110
continue ;
81
111
}
82
112
83
- if ( property . GetIndexParameters ( ) . Length != 0 )
113
+ var propertyType = property . PropertyType ;
114
+
115
+ if ( propertyType . GetTypeInfo ( ) . IsValueType && ! propertyType . GetTypeInfo ( ) . IsEnum )
84
116
{
85
117
continue ;
86
118
}
87
119
88
- if ( ! propertySelector . InjectProperty ( property , instance ) )
120
+ if ( propertyType . IsArray && propertyType . GetElementType ( ) . GetTypeInfo ( ) . IsValueType )
89
121
{
90
122
continue ;
91
123
}
92
124
93
- var setParameter = property . SetMethod . GetParameters ( ) . First ( ) ;
94
- var valueProvider = ( Func < object > ) null ;
95
- var parameter = parameters . FirstOrDefault ( p => p . CanSupplyValue ( setParameter , context , out valueProvider ) ) ;
96
- if ( parameter != null )
125
+ if ( propertyType . IsGenericEnumerableInterfaceType ( ) && propertyType . GetTypeInfo ( ) . GenericTypeArguments [ 0 ] . GetTypeInfo ( ) . IsValueType )
97
126
{
98
- property . SetValue ( instance , valueProvider ( ) , null ) ;
99
127
continue ;
100
128
}
101
129
102
- object propertyValue ;
103
- var propertyService = new TypedService ( propertyType ) ;
104
- var instanceTypeParameter = new NamedParameter ( InstanceTypeNamedParameter , instanceType ) ;
105
- if ( context . TryResolveService ( propertyService , new Parameter [ ] { instanceTypeParameter } , out propertyValue ) )
130
+ if ( property . GetIndexParameters ( ) . Length != 0 )
106
131
{
107
- property . SetValue ( instance , propertyValue , null ) ;
132
+ continue ;
108
133
}
134
+
135
+ yield return property ;
109
136
}
110
137
}
138
+
139
+ private static Action < object , object > MakeFastPropertySetter ( PropertyInfo propertyInfo )
140
+ {
141
+ var setMethod = propertyInfo . SetMethod ;
142
+ var typeInput = setMethod . DeclaringType ;
143
+ var parameters = setMethod . GetParameters ( ) ;
144
+ var parameterType = parameters [ 0 ] . ParameterType ;
145
+
146
+ // Create a delegate TDeclaringType -> { TDeclaringType.Property = TValue; }
147
+ var propertySetterAsAction = setMethod . CreateDelegate ( typeof ( Action < , > ) . MakeGenericType ( typeInput , parameterType ) ) ;
148
+ var callPropertySetterClosedGenericMethod = CallPropertySetterOpenGenericMethod . MakeGenericMethod ( typeInput , parameterType ) ;
149
+ var callPropertySetterDelegate = callPropertySetterClosedGenericMethod . CreateDelegate ( typeof ( Action < object , object > ) , propertySetterAsAction ) ;
150
+
151
+ return ( Action < object , object > ) callPropertySetterDelegate ;
152
+ }
153
+
154
+ private static void CallPropertySetter < TDeclaringType , TValue > (
155
+ Action < TDeclaringType , TValue > setter , object target , object value ) =>
156
+ setter ( ( TDeclaringType ) target , ( TValue ) value ) ;
111
157
}
112
158
}
0 commit comments