private void Transform(ModuleDefinition mod, MethodDefinition method, MethodDefinition newMethod, FieldDefinition expressionField, out TypeDefinition closureType) { var writer = newMethod.Body.GetILProcessor(); Dictionary <ParameterReference, VariableDefinition> oldParameterToNNewVariable = new Dictionary <ParameterReference, VariableDefinition>(); newMethod.Body.InitLocals = true; writer.Emit(OpCodes.Nop); var allParameters = method.Parameters.ToList(); if (method.Body.ThisParameter != null) { allParameters.Insert(0, method.Body.ThisParameter); } foreach (var p in allParameters) { var variable = new VariableDefinition(mod.ImportReference(ParameterExpression)); newMethod.Body.Variables.Add(variable); writer.Emit(OpCodes.Ldtoken, p.ParameterType); writer.Emit(OpCodes.Call, mod.ImportReference(this.Type_GetTypeFromHandle)); writer.Emit(OpCodes.Ldstr, p == method.Body.ThisParameter ? "this" : p.Name); writer.Emit(OpCodes.Call, mod.ImportReference(this.Expression_Parameter)); writer.Emit(OpCodes.Stloc, variable.Index); oldParameterToNNewVariable.Add(p, variable); } method.Body.SimplifyMacros(); var reader = new ILReader(method.Body); //var c = new <>__DisplayClass bool isDup = false; Dictionary <MetadataToken, ParameterReference> captureFieldToParameter = new Dictionary <MetadataToken, ParameterReference>(); closureType = null; if (reader.Is(OpCodes.Newobj)) { var newObj = reader.Get(OpCodes.Newobj); closureType = ((MethodDefinition)newObj.Operand).DeclaringType; if (reader.TryGet(OpCodes.Stloc) != null) //General case { //c.a = a; while (LookaheadClosureAssignment(isDup, ref reader, out var oldParameter, out var fieldReference)) { captureFieldToParameter.Add(fieldReference.MetadataToken, oldParameter); } } else if (reader.TryGet(OpCodes.Dup) != null) //only found for 1 parameter in release { isDup = true; if (!LookaheadClosureAssignment(isDup, ref reader, out var oldParameter, out var fieldReference)) { throw new InvalidOperationException($"Not expected (in {method.FullName})"); } captureFieldToParameter.Add(fieldReference.MetadataToken, oldParameter); } } Dictionary <VariableDefinition, VariableDefinition> rebasedVariables = new Dictionary <VariableDefinition, VariableDefinition>(); foreach (var v in method.Body.Variables) { if (closureType != null && v.VariableType == closureType) { } else { var newVariable = new VariableDefinition(mod.ImportReference(v.VariableType)); rebasedVariables.Add(v, newVariable); newMethod.Body.Variables.Add(newVariable); } } while (reader.HasMore()) { if (LookaheadExpressionFieldConstant(isDup, ref reader, out var token)) { var param = captureFieldToParameter[token.Value]; writer.Emit(OpCodes.Ldloc, oldParameterToNNewVariable[param].Index); } else if (!method.IsStatic && LookaheadExpressionThisConstant(ref reader, method.DeclaringType)) { writer.Emit(OpCodes.Ldloc, oldParameterToNNewVariable[method.Body.ThisParameter].Index); } else if (LookaheadArray(ref reader)) { if (reader.HasMore()) { throw new InvalidOperationException($"The method {method.FullName} should only call As.Expression with an expression tree lambda"); } if (oldParameterToNNewVariable.Count == 0) { writer.Emit(OpCodes.Call, mod.ImportReference(new GenericInstanceMethod(this.Array_Empty) { GenericArguments = { this.ParameterExpression } })); } else { writer.Emit(OpCodes.Ldc_I4, oldParameterToNNewVariable.Count); writer.Emit(OpCodes.Newarr, mod.ImportReference(this.ParameterExpression)); for (int i = 0; i < oldParameterToNNewVariable.Count; i++) { writer.Emit(OpCodes.Dup); writer.Emit(OpCodes.Ldc_I4, i); writer.Emit(OpCodes.Ldloc, i); writer.Emit(OpCodes.Stelem_Ref); } } var funcType = ((GenericInstanceType)expressionField.FieldType).GenericArguments.Single(); writer.Emit(OpCodes.Call, mod.ImportReference(new GenericInstanceMethod(this.Expression_Lambda) { GenericArguments = { funcType } })); writer.Emit(OpCodes.Stsfld, expressionField); writer.Emit(OpCodes.Ret); writer.Body.OptimizeMacros(); { method.Body.Instructions.Clear(); method.Body.Variables.Clear(); var oldWriter = method.Body.GetILProcessor(); oldWriter.Emit(OpCodes.Ldsfld, expressionField); for (int i = 0; i < allParameters.Count; i++) { oldWriter.Emit(OpCodes.Ldarg, allParameters[i]); } var evaluate = ExpressionExtensions.Methods.Single(a => a.Name == "Evaluate" && a.GenericParameters.Count == allParameters.Count + 1); var evaluateInstance = new GenericInstanceMethod(evaluate); foreach (var p in allParameters) { evaluateInstance.GenericArguments.Add(p.ParameterType); } evaluateInstance.GenericArguments.Add(method.ReturnType); oldWriter.Emit(OpCodes.Call, mod.ImportReference(evaluateInstance)); oldWriter.Emit(OpCodes.Ret); oldWriter.Body.Optimize(); } return; } else if (reader.TryGet(OpCodes.Ldloc) is Instruction ldloc) { writer.Emit(ldloc.OpCode, rebasedVariables[(VariableDefinition)ldloc.Operand]); } else if (reader.TryGet(OpCodes.Stloc) is Instruction stloc) { writer.Emit(stloc.OpCode, rebasedVariables[(VariableDefinition)stloc.Operand]); } else if (reader.TryGet(OpCodes.Ldloca) is Instruction ldloca) { writer.Emit(ldloca.OpCode, rebasedVariables[(VariableDefinition)ldloca.Operand]); } else { var ins = reader.Get(); writer.Append(ins); } } throw new InvalidOperationException($"The method {method.FullName} should only call As.Expression with an expression tree lambda"); }