@@ -20,6 +20,10 @@ internal static class TypedClientBuilder<T>
20
20
21
21
private static readonly PropertyInfo CancellationTokenNoneProperty = typeof ( CancellationToken ) . GetProperty ( "None" , BindingFlags . Public | BindingFlags . Static ) ;
22
22
23
+ private static readonly ConstructorInfo ObjectConstructor = typeof ( object ) . GetConstructors ( ) . Single ( ) ;
24
+
25
+ private static readonly Type [ ] ParameterTypes = new Type [ ] { typeof ( IClientProxy ) } ;
26
+
23
27
public static T Build ( IClientProxy proxy )
24
28
{
25
29
return _builder . Value ( proxy ) ;
@@ -40,20 +44,24 @@ private static Func<IClientProxy, T> GenerateClientBuilder()
40
44
var moduleBuilder = assemblyBuilder . DefineDynamicModule ( ClientModuleName ) ;
41
45
var clientType = GenerateInterfaceImplementation ( moduleBuilder ) ;
42
46
43
- return proxy => ( T ) Activator . CreateInstance ( clientType , proxy ) ;
47
+ var factoryMethod = clientType . GetMethod ( nameof ( Build ) , BindingFlags . Public | BindingFlags . Static ) ;
48
+ return ( Func < IClientProxy , T > ) factoryMethod . CreateDelegate ( typeof ( Func < IClientProxy , T > ) ) ;
44
49
}
45
50
46
51
private static Type GenerateInterfaceImplementation ( ModuleBuilder moduleBuilder )
47
52
{
48
- var type = moduleBuilder . DefineType (
49
- ClientModuleName + "." + typeof ( T ) . Name + "Impl" ,
50
- TypeAttributes . Public ,
51
- typeof ( Object ) ,
52
- new [ ] { typeof ( T ) } ) ;
53
+ var name = ClientModuleName + "." + typeof ( T ) . Name + "Impl" ;
54
+
55
+ var type = moduleBuilder . DefineType ( name , TypeAttributes . Public , typeof ( object ) , new [ ] { typeof ( T ) } ) ;
56
+
57
+ var proxyField = type . DefineField ( "_proxy" , typeof ( IClientProxy ) , FieldAttributes . Private | FieldAttributes . InitOnly ) ;
53
58
54
- var proxyField = type . DefineField ( "_proxy" , typeof ( IClientProxy ) , FieldAttributes . Private ) ;
59
+ var ctor = BuildConstructor ( type , proxyField ) ;
55
60
56
- BuildConstructor ( type , proxyField ) ;
61
+ // Because a constructor doesn't return anything, it can't be wrapped in a
62
+ // delegate directly, so we emit a factory method that just takes the IClientProxy,
63
+ // invokes the constructor (using newobj) and returns the new instance of type T.
64
+ BuildFactoryMethod ( type , ctor ) ;
57
65
58
66
foreach ( var method in GetAllInterfaceMethods ( typeof ( T ) ) )
59
67
{
@@ -79,27 +87,23 @@ private static IEnumerable<MethodInfo> GetAllInterfaceMethods(Type interfaceType
79
87
}
80
88
}
81
89
82
- private static void BuildConstructor ( TypeBuilder type , FieldInfo proxyField )
90
+ private static ConstructorInfo BuildConstructor ( TypeBuilder type , FieldInfo proxyField )
83
91
{
84
- var method = type . DefineMethod ( ".ctor" , System . Reflection . MethodAttributes . Public | System . Reflection . MethodAttributes . HideBySig ) ;
92
+ var ctor = type . DefineConstructor ( MethodAttributes . Public , CallingConventions . Standard , ParameterTypes ) ;
85
93
86
- var ctor = typeof ( object ) . GetConstructor ( BindingFlags . Instance | BindingFlags . Public | BindingFlags . NonPublic ,
87
- null , new Type [ ] { } , null ) ;
88
-
89
- method . SetReturnType ( typeof ( void ) ) ;
90
- method . SetParameters ( typeof ( IClientProxy ) ) ;
91
-
92
- var generator = method . GetILGenerator ( ) ;
94
+ var generator = ctor . GetILGenerator ( ) ;
93
95
94
96
// Call object constructor
95
97
generator . Emit ( OpCodes . Ldarg_0 ) ;
96
- generator . Emit ( OpCodes . Call , ctor ) ;
98
+ generator . Emit ( OpCodes . Call , ObjectConstructor ) ;
97
99
98
100
// Assign constructor argument to the proxyField
99
101
generator . Emit ( OpCodes . Ldarg_0 ) ; // type
100
102
generator . Emit ( OpCodes . Ldarg_1 ) ; // type proxyfield
101
103
generator . Emit ( OpCodes . Stfld , proxyField ) ; // type.proxyField = proxyField
102
104
generator . Emit ( OpCodes . Ret ) ;
105
+
106
+ return ctor ;
103
107
}
104
108
105
109
private static void BuildMethod ( TypeBuilder type , MethodInfo interfaceMethodInfo , FieldInfo proxyField )
@@ -187,6 +191,17 @@ private static void BuildMethod(TypeBuilder type, MethodInfo interfaceMethodInfo
187
191
generator . Emit ( OpCodes . Ret ) ; // Return the Task returned by 'invokeMethod'
188
192
}
189
193
194
+ private static void BuildFactoryMethod ( TypeBuilder type , ConstructorInfo ctor )
195
+ {
196
+ var method = type . DefineMethod ( nameof ( Build ) , MethodAttributes . Public | MethodAttributes . Static , CallingConventions . Standard , typeof ( T ) , ParameterTypes ) ;
197
+
198
+ var generator = method . GetILGenerator ( ) ;
199
+
200
+ generator . Emit ( OpCodes . Ldarg_0 ) ; // Load the IClientProxy argument onto the stack
201
+ generator . Emit ( OpCodes . Newobj , ctor ) ; // Call the generated constructor with the proxy
202
+ generator . Emit ( OpCodes . Ret ) ; // Return the typed client
203
+ }
204
+
190
205
private static void VerifyInterface ( Type interfaceType )
191
206
{
192
207
if ( ! interfaceType . IsInterface )
@@ -206,7 +221,7 @@ private static void VerifyInterface(Type interfaceType)
206
221
207
222
foreach ( var method in interfaceType . GetMethods ( ) )
208
223
{
209
- VerifyMethod ( interfaceType , method ) ;
224
+ VerifyMethod ( method ) ;
210
225
}
211
226
212
227
foreach ( var parent in interfaceType . GetInterfaces ( ) )
@@ -215,7 +230,7 @@ private static void VerifyInterface(Type interfaceType)
215
230
}
216
231
}
217
232
218
- private static void VerifyMethod ( Type interfaceType , MethodInfo interfaceMethod )
233
+ private static void VerifyMethod ( MethodInfo interfaceMethod )
219
234
{
220
235
if ( interfaceMethod . ReturnType != typeof ( Task ) )
221
236
{
0 commit comments