@@ -126,6 +126,7 @@ private static DynFunc Construct(object target, MethodInfo method)
126126 hasThis ? new [ ] { typeof ( object ) , typeof ( Remote ) , typeof ( object [ ] ) } : new [ ] { typeof ( Remote ) , typeof ( object [ ] ) } ) ;
127127
128128 ILGenerator g = lambda . GetILGenerator ( ) ;
129+ g . DeclareLocal ( typeof ( uint ) ) ;
129130
130131 OpCode ldarg_remote , ldarg_args ;
131132 if ( hasThis )
@@ -141,8 +142,13 @@ private static DynFunc Construct(object target, MethodInfo method)
141142 ldarg_args = OpCodes . Ldarg_1 ;
142143 }
143144
145+ g . Emit ( ldarg_args ) ;
146+ g . Emit ( OpCodes . Ldlen ) ;
147+ g . Emit ( OpCodes . Stloc_0 ) ;
144148 for ( int i = 0 , p = 0 ; i < parameters . Length ; ++ i )
145149 {
150+ Label lblOutOfRange = g . DefineLabel ( ) ;
151+ Label lblNextArgument = g . DefineLabel ( ) ;
146152 var parameter = parameters [ i ] ;
147153 var t = parameter . ParameterType ;
148154
@@ -176,27 +182,15 @@ private static DynFunc Construct(object target, MethodInfo method)
176182 throw new ArgumentException ( $ "{ nameof ( SourceAttribute ) } used on type { t } , this type can't be constructed with parameter Remote.") ;
177183 }
178184
185+ g . Emit ( OpCodes . Ldc_I4 , p ) ;
186+ g . Emit ( OpCodes . Ldloc_0 ) ;
187+ g . Emit ( OpCodes . Bge_Un , lblOutOfRange ) ;
179188 g . Emit ( ldarg_args ) ;
180189 g . Emit ( OpCodes . Ldc_I4_S , ( byte ) p ++ ) ;
181190 g . Emit ( OpCodes . Ldelem_Ref ) ;
182191
183192 if ( t . IsValueType )
184193 {
185- Label diff = g . DefineLabel ( ) ;
186- Label done = g . DefineLabel ( ) ;
187-
188- g . Emit ( OpCodes . Dup ) ;
189-
190- // check if given type is already of the target type
191- g . Emit ( OpCodes . Isinst , t ) ;
192- g . Emit ( OpCodes . Brfalse_S , diff ) ;
193-
194- // same type, unbox and pass it as an argument
195- g . Emit ( OpCodes . Unbox_Any , t ) ;
196- g . Emit ( OpCodes . Br , done ) ;
197-
198- // not the same type, try and convert it
199- g . MarkLabel ( diff ) ;
200194 if ( t . IsPrimitive )
201195 {
202196 g . Emit ( OpCodes . Call , convertMethods [ t ] ) ; // already handles null
@@ -206,14 +200,46 @@ private static DynFunc Construct(object target, MethodInfo method)
206200 g . Emit ( OpCodes . Pop ) ;
207201 g . Emit ( OpCodes . Ldloc_S , g . DeclareLocal ( t ) ) ;
208202 }
209-
210- g . MarkLabel ( done ) ;
211203 }
212204 else if ( t != typeof ( object ) )
213205 {
214206 g . Emit ( OpCodes . Castclass , t ) ; // throwing cast, exception on fail
215207 //g.Emit(OpCodes.Isinst, t); // non throwing cast, null on fail
216208 }
209+ g . Emit ( OpCodes . Br , lblNextArgument ) ;
210+
211+ g . MarkLabel ( lblOutOfRange ) ;
212+ if ( parameter . IsOptional )
213+ {
214+ switch ( parameter . DefaultValue )
215+ {
216+ case null : g . Emit ( OpCodes . Ldnull ) ; break ;
217+ case string v : g . Emit ( OpCodes . Ldstr , v ) ; break ;
218+ case byte v : g . Emit ( OpCodes . Ldc_I4 , v ) ; break ;
219+ case ushort v : g . Emit ( OpCodes . Ldc_I4 , v ) ; break ;
220+ case uint v : g . Emit ( OpCodes . Ldc_I4 , v ) ; break ;
221+ case ulong v : g . Emit ( OpCodes . Ldc_I4 , v ) ; break ;
222+ case sbyte v : g . Emit ( OpCodes . Ldc_I4 , v ) ; break ;
223+ case short v : g . Emit ( OpCodes . Ldc_I4 , v ) ; break ;
224+ case int v : g . Emit ( OpCodes . Ldc_I4 , v ) ; break ;
225+ }
226+
227+ // Generic way to also support Nullable<> types
228+ if ( t . IsGenericType )
229+ {
230+ Type [ ] genericArguments = t . GetGenericArguments ( ) ;
231+ if ( genericArguments . Length == 1 )
232+ g . Emit ( OpCodes . Newobj , t . GetConstructor ( genericArguments ) ) ;
233+ else
234+ throw new ArgumentException ( $ "Default value for { t } is unsupported.") ;
235+ }
236+ }
237+ else
238+ {
239+ g . Emit ( OpCodes . Newobj , typeof ( IndexOutOfRangeException ) . GetConstructor ( Type . EmptyTypes ) ) ;
240+ g . Emit ( OpCodes . Throw ) ;
241+ }
242+ g . MarkLabel ( lblNextArgument ) ;
217243 }
218244
219245#if DYN_FUNC_CALLI
0 commit comments