private static void GenerateCallerMethod(GeneratorContext context) { if (context.Parameters.Length != 0) { return; } MethodBase baseMethod; Type returnType; if (context.CallerType == CallerType.Ctor) { baseMethod = context.Constructor; returnType = null; } else { baseMethod = context.Method; returnType = context.Method.ReturnType; } var method = context.TypeBuilder.DefineMethod( $"<{baseMethod.Name}>_{context.Token}", MethodAttributes.Private | MethodAttributes.HideBySig, CallingConventions.HasThis | CallingConventions.Standard, returnType, context.Parameters.Select(x => x.Type).ToArray() ); method.SetMethodParameters(baseMethod, baseMethod.GetParameters()); var generator = method.GetILGenerator(); generator.Emit(OpCodes.Ldarg_0); if (context.Parameters.Length > 0) { for (var i = 1; i <= context.Parameters.Length; i++) { generator.Emit(OpCodes.Ldarg_S, i); } } if (context.InterfaceMethod == null) { if (context.CallerType == CallerType.Ctor) { generator.Emit(OpCodes.Call, context.Constructor); } else { generator.Emit(OpCodes.Call, context.Method); } } else { generator.Emit(OpCodes.Ldfld, context.Interface); generator.Emit(OpCodes.Callvirt, context.InterfaceMethod); } generator.Emit(OpCodes.Ret); context.CallerMethod = method; }
private static void MethodBodSetp4(GeneratorContext context, ILGenerator generator) { var callerType = context.CallerType; var parameters = context.Parameters; if (parameters.Length > 0) { // Action or Func<T> call = () => base.Method(xx); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ldftn, context.DisplayMethod); generator.Emit(OpCodes.Newobj, context.CallType.GetConstructors()[0]); generator.Emit(OpCodes.Stloc_2); // T result = this._caller.Call(this, call, parameters); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldfld, context.Caller); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldloc_2); generator.Emit(OpCodes.Ldloc_1); generator.Emit(OpCodes.Callvirt, context.Caller.FieldType.GetMethod( "Call", BindingFlags.Public | BindingFlags.Instance )); for (var i = 1; i <= parameters.Length; i++) { var parameter = parameters[i - 1]; if (parameter.IsOut || parameter.IsRef) { var field = context.DisplayFields[i]; generator.Emit(OpCodes.Ldarg_S, i); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ldfld, field); if (field.FieldType.IsValueType) { generator.Emit(OpCodes.Stobj, field.FieldType); } else { generator.Emit(OpCodes.Stind_Ref); } } } } else { generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldftn, context.CallerMethod); generator.Emit(OpCodes.Newobj, context.CallType.GetConstructors()[0]); generator.Emit(OpCodes.Stloc_0); // this._caller.Call(this, call, null); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldfld, context.Caller); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ldnull); generator.Emit(OpCodes.Callvirt, context.Caller.FieldType.GetMethod( "Call", BindingFlags.Public | BindingFlags.Instance )); } generator.Emit(OpCodes.Ret); }
private static GeneratorContext GetMethodContext( MethodBase builder, MethodBase proxyMethod, MethodInfo interfaceMethod, ILGenerator generator, GeneratorTypeContext typeContext, ParameterInfo[] parameters ) { var context = new GeneratorContext(typeContext) { Generator = generator, InterfaceMethod = interfaceMethod, Parameters = proxyMethod.GetParameters().Select(x => new ParamInfo(x)).ToArray() }; Type fieldType; if (proxyMethod is MethodInfo meth) { context.Method = meth; var returnType = meth.ReturnType; if (returnType.IsByRef) { context.ReturnType = returnType; } else { if (returnType == typeof(void)) { context.ReturnType = returnType; context.CallerType = CallerType.Void; fieldType = typeof(VoidCaller); } else if (!meth.IsDefined(typeof(StateMachineAttribute))) { context.ReturnType = returnType; context.CallerType = CallerType.Return; fieldType = typeof(ReturnCaller <>).MakeGenericType(returnType); } else if (returnType == typeof(Task)) { context.ReturnType = null; context.CallerType = CallerType.Task; fieldType = typeof(TaskCaller); } else if (returnType.IsGenericType) { var type = returnType.GetGenericTypeDefinition(); context.ReturnType = returnType.GetGenericArguments()[0]; if (type == typeof(Task <>)) { context.CallerType = CallerType.TaskOfT; fieldType = typeof(TaskCaller <>).MakeGenericType(context.ReturnType); } else if (type == typeof(ValueTask <>)) { context.CallerType = CallerType.ValueTaskOfT; fieldType = typeof(ValueTaskCaller <>).MakeGenericType(context.ReturnType); } else { throw new InvalidOperationException("function return value error!"); } } else { throw new InvalidOperationException("function return value error!"); } context.Caller = context.TypeBuilder.DefineField($"<>_caller{context.Token}", fieldType, FieldAttributes.Private); context.MethodBuilder = (MethodBuilder)builder; } } else if (proxyMethod is ConstructorInfo ctor) { context.Constructor = ctor; context.ReturnType = null; context.CallerType = CallerType.Ctor; context.Caller = context.TypeBuilder.DefineField($"<>_caller{context.Token}", typeof(VoidCaller), FieldAttributes.Private); context.ConstructorBuilder = (ConstructorBuilder)builder; } return(context); }
private static void MethodBodSetp3(GeneratorContext context, ILGenerator generator) { if (context.Parameters.Length == 0) { return; } var parameters = context.Parameters; var displayFields = context.DisplayFields; generator.Emit(OpCodes.Ldc_I4, parameters.Length); generator.Emit(OpCodes.Newarr, typeof(object)); generator.Emit(OpCodes.Stloc_1); for (var i = 1; i <= parameters.Length; i++) { var parameter = parameters[i - 1]; var displayField = displayFields[i]; generator.Emit(OpCodes.Ldloc_0); if (parameter.IsOut) { if (displayField.FieldType.IsValueType) { generator.Emit(OpCodes.Ldflda, displayField); generator.Emit(OpCodes.Initobj, displayField.FieldType); } else { generator.Emit(OpCodes.Ldnull); generator.Emit(OpCodes.Stfld, displayField); } } else if (parameter.IsRef) { generator.Emit(OpCodes.Ldarg_S, i); if (displayField.FieldType.IsValueType) { generator.Emit(OpCodes.Ldobj, displayField.FieldType); } else { generator.Emit(OpCodes.Ldind_Ref); } generator.Emit(OpCodes.Stfld, displayField); } else { generator.Emit(OpCodes.Ldarg_S, i); generator.Emit(OpCodes.Stfld, displayField); } generator.Emit(OpCodes.Ldloc_1); generator.Emit(OpCodes.Ldc_I4, i - 1); if (parameter.IsOut) { generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ldfld, displayField); if (displayField.FieldType.IsValueType) { generator.Emit(OpCodes.Box, displayField.FieldType); } } else if (parameter.IsRef) { generator.Emit(OpCodes.Ldarg_S, i); if (displayField.FieldType.IsValueType) { generator.Emit(OpCodes.Ldobj, displayField.FieldType); generator.Emit(OpCodes.Box, displayField.FieldType); } else { generator.Emit(OpCodes.Ldind_Ref); } } else { generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ldfld, displayField); if (displayField.FieldType.IsValueType) { generator.Emit(OpCodes.Box, displayField.FieldType); } } generator.Emit(OpCodes.Stelem_Ref); } }