private void BuildMethod( TypeBuilder builder, ILGenerator gen, MethodBodyReader reader, Type[] realParameters, Dictionary <string, FieldBuilder> fields, Dictionary <string, InterimMethod> methods, string memberName) { var fakeParameters = reader.Method.GetParameters().Skip(1).Select(p => p.ParameterType).ToArray(); var fakeReturn = (reader.Method as MethodInfo)?.ReturnType; var writer = new MethodBodyBuilder(gen); var locals = reader.Locals.Select(lc => lc.LocalType); writer.DeclareLocals(locals); writer.DeclareExceptionHandlers(reader.ExceptionHandlers); // transforms all ldarg.x to ldarg.x-1 and output the index of the new ldarg.0's (context calls) int[] contexts; var body = TransformLdArgOpcodes(reader.Instructions, realParameters, fakeParameters, out contexts); // starts at the innermost context call and walks back to the beginning replacing them. foreach (var startIndex in contexts.OrderByDescending(x => x)) { var endIndex = startIndex; while (endIndex < body.Length) { endIndex++; var endOp = body[endIndex]; if (endOp.OpCode == OpCodes.Callvirt && DynamicClassContext.Methods.Contains(endOp.Operand as MethodInfo)) { break; } } endIndex++; var ins = body.Skip(startIndex).Take(endIndex - startIndex).ToArray(); ins = ProcessLdContextInstruction(ins, fields, methods, memberName); body = body.Take(startIndex).Concat(ins).Concat(body.Skip(endIndex)).ToArray(); } var returnType = methods.ContainsKey(memberName) ? methods[memberName].Builder.ReturnType : null; if (returnType?.IsValueType == true && returnType != typeof(void) && fakeReturn != returnType) { var lbody = body.ToList(); // unbox any return values foreach (var ret in lbody.Select((s, i) => new { Index = i, Instruction = s }).Where(o => o.Instruction.OpCode == OpCodes.Ret).OrderByDescending(inf => inf.Index).ToArray()) { lbody.Insert(ret.Index, new Instruction(-1, OpCodes.Unbox_Any) { Operand = returnType }); } writer.EmitBody(lbody); } else { writer.EmitBody(body); } }
public static void BuildFromExistingMethod(string newMethodName, MethodInfo originalMethod, TypeBuilder builder) { var tMethod = builder.DefineMethod(newMethodName, originalMethod.Attributes, originalMethod.CallingConvention, originalMethod.ReturnType, originalMethod.GetParameters().Select(p => p.ParameterType).ToArray()); var reader = MethodBodyReader.Read(originalMethod); MethodBodyBuilder bb = new MethodBodyBuilder(tMethod); bb.DeclareLocals(reader.Locals.Select(l => l.LocalType)); bb.DeclareExceptionHandlers(reader.ExceptionHandlers); bb.EmitBody(reader.Instructions); }
public static void BuildFromExistingMethod(string newMethodName, MethodInfo originalMethod, TypeBuilder builder) { var tMethod = builder.DefineMethod(newMethodName, originalMethod.Attributes, originalMethod.CallingConvention, originalMethod.ReturnType, originalMethod.GetParameters().Select(p => p.ParameterType).ToArray()); var reader = MethodBodyReader.Read(originalMethod); MethodBodyBuilder bb = new MethodBodyBuilder(tMethod.GetILGenerator()); bb.DeclareLocals(reader.Locals.Select(l => l.LocalType)); bb.DeclareExceptionHandlers(reader.ExceptionHandlers); bb.EmitBody(reader.Instructions); }