public void Decorate(TypeDefinition type, MethodDefinition method, CustomAttribute attribute, bool explicitMatch) { method.Body.InitLocals = true; var parametersArrayTypeRef = new ArrayType(objectTypeRef); var initMethodRef1 = referenceFinder.GetOptionalMethodReference(attribute.AttributeType, md => md.Name == "Init" && md.Parameters.Count == 1 && md.Parameters[0].ParameterType.FullName == typeof(MethodBase).FullName); var initMethodRef2 = referenceFinder.GetOptionalMethodReference(attribute.AttributeType, md => md.Name == "Init" && md.Parameters.Count == 2 && md.Parameters[0].ParameterType.FullName == typeof(object).FullName); var initMethodRef3 = referenceFinder.GetOptionalMethodReference(attribute.AttributeType, md => md.Name == "Init" && md.Parameters.Count == 3); var needBypassRef0 = referenceFinder.GetOptionalMethodReference(attribute.AttributeType, md => md.Name == "NeedBypass" && md.Parameters.Count == 0); var onEntryMethodRef0 = referenceFinder.GetOptionalMethodReference(attribute.AttributeType, md => md.Name == "OnEntry" && md.Parameters.Count == 0); var onExitMethodRef0 = referenceFinder.GetOptionalMethodReference(attribute.AttributeType, md => md.Name == "OnExit" && md.Parameters.Count == 0); var onExitMethodRef1 = referenceFinder.GetOptionalMethodReference(attribute.AttributeType, md => md.Name == "OnExit" && md.Parameters.Count == 1 && md.Parameters[0].ParameterType.FullName == typeof(object).FullName); var alterRetvalRef1 = referenceFinder.GetOptionalMethodReference(attribute.AttributeType, md => md.Name == "AlterRetval" && md.Parameters.Count == 1); var onExceptionMethodRef = referenceFinder.GetOptionalMethodReference(attribute.AttributeType, md => md.Name == "OnException" && md.Parameters.Count == 1 && md.Parameters[0].ParameterType.FullName == typeof(Exception).FullName); var taskContinuationMethodRef = referenceFinder.GetOptionalMethodReference(attribute.AttributeType, md => md.Name == "OnTaskContinuation"); var attributeVariableDefinition = AddVariableDefinition(method, "__fody$attribute", attribute.AttributeType); var methodVariableDefinition = AddVariableDefinition(method, "__fody$method", methodBaseTypeRef); VariableDefinition exceptionVariableDefinition = null; VariableDefinition parametersVariableDefinition = null; VariableDefinition retvalVariableDefinition = null; if (initMethodRef3 != null) { parametersVariableDefinition = AddVariableDefinition(method, "__fody$parameters", parametersArrayTypeRef); } if (onExceptionMethodRef != null) { exceptionVariableDefinition = AddVariableDefinition(method, "__fody$exception", exceptionTypeRef); } var needCatchReturn = null != (onExitMethodRef1 ?? onExitMethodRef0 ?? onExceptionMethodRef ?? taskContinuationMethodRef ?? alterRetvalRef1 ?? needBypassRef0); if (method.ReturnType.FullName != "System.Void" && needCatchReturn) { retvalVariableDefinition = AddVariableDefinition(method, "__fody$retval", method.ReturnType); } method.Body.SimplifyMacros(); var processor = method.Body.GetILProcessor(); var methodBodyFirstInstruction = method.Body.Instructions.First(); if (method.IsConstructor) { var callBase = method.Body.Instructions.FirstOrDefault( i => i.OpCode == OpCodes.Call && (i.Operand is MethodReference reference) && reference.Resolve().IsConstructor); methodBodyFirstInstruction = callBase?.Next ?? methodBodyFirstInstruction; } var initAttributeVariable = GetAttributeInstanceInstructions(processor, attribute, method, attributeVariableDefinition, methodVariableDefinition, explicitMatch); List <Instruction> callInitInstructions = null; List <Instruction> createParametersArrayInstructions = null; List <Instruction> callOnEntryInstructions = null; List <Instruction> saveRetvalInstructions = null; List <Instruction> callOnExitInstructions = null; if (parametersVariableDefinition != null) { createParametersArrayInstructions = CreateParametersArrayInstructions( processor, method, parametersVariableDefinition).ToList(); } var initMethodRef = initMethodRef3 ?? initMethodRef2 ?? initMethodRef1; if (initMethodRef != null) { callInitInstructions = GetCallInitInstructions( processor, type, method, attributeVariableDefinition, methodVariableDefinition, parametersVariableDefinition, initMethodRef).ToList(); } if (onEntryMethodRef0 != null) { callOnEntryInstructions = GetCallOnEntryInstructions(processor, attributeVariableDefinition, onEntryMethodRef0).ToList(); } if (retvalVariableDefinition != null) { saveRetvalInstructions = GetSaveRetvalInstructions(processor, retvalVariableDefinition).ToList(); } if (retvalVariableDefinition != null && onExitMethodRef1 != null) { callOnExitInstructions = GetCallOnExitInstructions(processor, attributeVariableDefinition, onExitMethodRef1, retvalVariableDefinition).ToList(); } else if (onExitMethodRef0 != null) { callOnExitInstructions = GetCallOnExitInstructions(processor, attributeVariableDefinition, onExitMethodRef0).ToList(); } List <Instruction> methodBodyReturnInstructions = null; List <Instruction> tryCatchLeaveInstructions = null; List <Instruction> catchHandlerInstructions = null; List <Instruction> bypassInstructions = null; if (needCatchReturn) { methodBodyReturnInstructions = GetMethodBodyReturnInstructions(processor, attributeVariableDefinition, retvalVariableDefinition, alterRetvalRef1).ToList(); if (needBypassRef0 != null) { bypassInstructions = GetBypassInstructions(processor, attributeVariableDefinition, needBypassRef0, methodBodyReturnInstructions.First()).ToList(); } if (onExceptionMethodRef != null) { tryCatchLeaveInstructions = GetTryCatchLeaveInstructions(processor, methodBodyReturnInstructions.First()).ToList(); catchHandlerInstructions = GetCatchHandlerInstructions(processor, attributeVariableDefinition, exceptionVariableDefinition, onExceptionMethodRef); } ReplaceRetInstructions(processor, saveRetvalInstructions?.FirstOrDefault() ?? callOnExitInstructions?.FirstOrDefault() ?? methodBodyReturnInstructions.First()); } processor.InsertBefore(methodBodyFirstInstruction, initAttributeVariable); if (createParametersArrayInstructions != null) { processor.InsertBefore(methodBodyFirstInstruction, createParametersArrayInstructions); } if (callInitInstructions != null) { processor.InsertBefore(methodBodyFirstInstruction, callInitInstructions); } if (bypassInstructions != null) { processor.InsertBefore(methodBodyFirstInstruction, bypassInstructions); } if (callOnEntryInstructions != null) { processor.InsertBefore(methodBodyFirstInstruction, callOnEntryInstructions); } if (methodBodyReturnInstructions != null) { processor.InsertAfter(method.Body.Instructions.Last(), methodBodyReturnInstructions); if (saveRetvalInstructions != null) { processor.InsertBefore(methodBodyReturnInstructions.First(), saveRetvalInstructions); } if (taskContinuationMethodRef != null) { var taskContinuationInstructions = GetTaskContinuationInstructions( processor, retvalVariableDefinition, attributeVariableDefinition, taskContinuationMethodRef); processor.InsertBefore(methodBodyReturnInstructions.First(), taskContinuationInstructions); } if (callOnExitInstructions != null) { processor.InsertBefore(methodBodyReturnInstructions.First(), callOnExitInstructions); } if (onExceptionMethodRef != null) { processor.InsertBefore(methodBodyReturnInstructions.First(), tryCatchLeaveInstructions); processor.InsertBefore(methodBodyReturnInstructions.First(), catchHandlerInstructions); method.Body.ExceptionHandlers.Add(new ExceptionHandler(ExceptionHandlerType.Catch) { CatchType = exceptionTypeRef, TryStart = methodBodyFirstInstruction, TryEnd = tryCatchLeaveInstructions.Last().Next, HandlerStart = catchHandlerInstructions.First(), HandlerEnd = catchHandlerInstructions.Last().Next }); } } method.Body.OptimizeMacros(); }