@@ -25,13 +25,16 @@ public static class LazyProxyBuilder
25
25
private static readonly ConcurrentDictionary < Type , Lazy < Type > > ProxyTypes =
26
26
new ConcurrentDictionary < Type , Lazy < Type > > ( ) ;
27
27
28
+ private static readonly MethodInfo CreateLazyMethod = typeof ( LazyBuilder )
29
+ . GetMethod ( "CreateInstance" , BindingFlags . Public | BindingFlags . Static ) ;
30
+
28
31
/// <summary>
29
32
/// Defines at runtime a class that implements interface T
30
33
/// and proxies all invocations to <see cref="Lazy{T}"/> of this interface.
31
34
/// </summary>
32
35
/// <typeparam name="T">The interface proxy type implements.</typeparam>
33
36
/// <returns>The lazy proxy type.</returns>
34
- public static Type GetType < T > ( )
37
+ public static Type GetType < T > ( ) where T : class
35
38
{
36
39
return GetType ( typeof ( T ) ) ;
37
40
}
@@ -50,10 +53,18 @@ public static Type GetType(Type type)
50
53
throw new NotSupportedException ( "The lazy proxy is supported only for interfaces." ) ;
51
54
}
52
55
56
+ var interfaceType = type . IsConstructedGenericType
57
+ ? type . GetGenericTypeDefinition ( )
58
+ : type ;
59
+
53
60
// Lazy is used to guarantee the valueFactory is invoked only once.
54
61
// More info: http://reedcopsey.com/2011/01/16/concurrentdictionarytkeytvalue-used-with-lazyt/
55
- var lazy = ProxyTypes . GetOrAdd ( type , t => new Lazy < Type > ( ( ) => DefineProxyType ( t ) ) ) ;
56
- return lazy . Value ;
62
+ var lazy = ProxyTypes . GetOrAdd ( interfaceType , t => new Lazy < Type > ( ( ) => DefineProxyType ( t ) ) ) ;
63
+ var proxyType = lazy . Value ;
64
+
65
+ return type . IsConstructedGenericType
66
+ ? proxyType . MakeGenericType ( type . GetGenericArguments ( ) )
67
+ : proxyType ;
57
68
}
58
69
59
70
/// <summary>
@@ -62,11 +73,27 @@ public static Type GetType(Type type)
62
73
/// <param name="valueFactory">The function real value returns.</param>
63
74
/// <typeparam name="T">The interface proxy type implements.</typeparam>
64
75
/// <returns>The lazy proxy type instance.</returns>
65
- public static T CreateInstance < T > ( Func < T > valueFactory )
76
+ public static T CreateInstance < T > ( Func < T > valueFactory ) where T : class
66
77
{
67
- var lazy = new Lazy < T > ( valueFactory ) ;
68
- var proxyType = GetType < T > ( ) ;
69
- return ( T ) Activator . CreateInstance ( proxyType , lazy ) ;
78
+ return ( T ) CreateInstance ( typeof ( T ) , valueFactory ) ;
79
+ }
80
+
81
+ /// <summary>
82
+ /// Creates a lazy proxy type instance using a value factory.
83
+ /// </summary>
84
+ /// <param name="type">The interface proxy type implements.</param>
85
+ /// <param name="valueFactory">The function real value returns.</param>
86
+ /// <returns>The lazy proxy type instance.</returns>
87
+ public static object CreateInstance ( Type type , Func < object > valueFactory )
88
+ {
89
+ var proxyType = GetType ( type ) ;
90
+
91
+ // Using 'Initialize' method after the instance creation allows to improve performance
92
+ // because Activator.CreateInstance executed with arguments is much slower.
93
+ var instance = ( LazyProxyBase ) Activator . CreateInstance ( proxyType ) ;
94
+ instance . Initialize ( valueFactory ) ;
95
+
96
+ return instance ;
70
97
}
71
98
72
99
/// <summary>
@@ -81,9 +108,9 @@ public static T CreateInstance<T>(Func<T> valueFactory)
81
108
/// {
82
109
/// private Lazy<IMyService> _service;
83
110
///
84
- /// public LazyProxyImpl_1eb94ccd79fd48af8adfbc97c76c10ff_IMyService(Lazy<IMyService> service )
111
+ /// public void Initialize(Func<object> valueFactory )
85
112
/// {
86
- /// _service = service ;
113
+ /// _service = LazyBuilder.CreateInstance<IMyService>(valueFactory) ;
87
114
/// }
88
115
///
89
116
/// public void Foo() => _service.Value.Foo();
@@ -101,11 +128,11 @@ private static Type DefineProxyType(Type type)
101
128
102
129
var typeName = $ "{ type . Namespace } .{ LazyProxyTypeSuffix } _{ guid } _{ type . Name } ";
103
130
104
- return ModuleBuilder . DefineType ( typeName , TypeAttributes . Public )
131
+ return ModuleBuilder . DefineType ( typeName , TypeAttributes . Public , typeof ( LazyProxyBase ) )
105
132
. AddGenericParameters ( type )
106
133
. AddInterface ( type )
107
134
. AddServiceField ( type , out var serviceField )
108
- . AddConstructor ( type , serviceField )
135
+ . AddInitializeMethod ( type , serviceField )
109
136
. AddMethods ( type , serviceField )
110
137
. CreateTypeInfo ( ) ;
111
138
}
@@ -137,18 +164,22 @@ private static TypeBuilder AddServiceField(this TypeBuilder typeBuilder,
137
164
return typeBuilder ;
138
165
}
139
166
140
- private static TypeBuilder AddConstructor ( this TypeBuilder typeBuilder , Type type , FieldInfo serviceField )
167
+ private static TypeBuilder AddInitializeMethod ( this TypeBuilder typeBuilder , Type type , FieldInfo serviceField )
141
168
{
142
- var constructorBuilder = typeBuilder . DefineConstructor (
143
- MethodAttributes . Public ,
144
- CallingConventions . Standard ,
145
- new [ ] { typeof ( Lazy < > ) . MakeGenericType ( type ) }
169
+ var methodBuilder = typeBuilder . DefineMethod (
170
+ "Initialize" ,
171
+ MethodAttributes . Public | MethodAttributes . Virtual ,
172
+ null ,
173
+ new [ ] { typeof ( Func < object > ) }
146
174
) ;
147
175
148
- var generator = constructorBuilder . GetILGenerator ( ) ;
176
+ var createLazyMethod = CreateLazyMethod . MakeGenericMethod ( type ) ;
177
+
178
+ var generator = methodBuilder . GetILGenerator ( ) ;
149
179
150
180
generator . Emit ( OpCodes . Ldarg_0 ) ;
151
181
generator . Emit ( OpCodes . Ldarg_1 ) ;
182
+ generator . Emit ( OpCodes . Call , createLazyMethod ) ;
152
183
generator . Emit ( OpCodes . Stfld , serviceField ) ;
153
184
generator . Emit ( OpCodes . Ret ) ;
154
185
0 commit comments