public void Decorate(TypeDefinition type, MethodDefinition method, CustomAttribute attribute)
{
method.Body.InitLocals = true;
var methodBaseTypeRef = this._referenceFinder.GetTypeReference(typeof(MethodBase));
var exceptionTypeRef = this._referenceFinder.GetTypeReference(typeof(Exception));
var parameterTypeRef = this._referenceFinder.GetTypeReference(typeof(object));
var parametersArrayTypeRef = new ArrayType(parameterTypeRef);
var methodVariableDefinition = AddVariableDefinition(method, "__fody$method", methodBaseTypeRef);
var attributeVariableDefinition = AddVariableDefinition(method, "__fody$attribute", attribute.AttributeType);
var exceptionVariableDefinition = AddVariableDefinition(method, "__fody$exception", exceptionTypeRef);
var parametersVariableDefinition = AddVariableDefinition(method, "__fody$parameters", parametersArrayTypeRef);
VariableDefinition retvalVariableDefinition = null;
if (method.ReturnType.FullName != "System.Void")
retvalVariableDefinition = AddVariableDefinition(method, "__fody$retval", method.ReturnType);
var initMethodRef = this._referenceFinder.GetOptionalMethodReference(attribute.AttributeType, md => md.Name == "Init");
var onEntryMethodRef = this._referenceFinder.GetMethodReference(attribute.AttributeType, md => md.Name == "OnEntry");
var onExitMethodRef = this._referenceFinder.GetMethodReference(attribute.AttributeType, md => md.Name == "OnExit");
var onExceptionMethodRef = this._referenceFinder.GetMethodReference(attribute.AttributeType, md => md.Name == "OnException");
var taskContinuationMethodRef = this._referenceFinder.GetOptionalMethodReference(attribute.AttributeType, md => md.Name == "OnTaskContinuation");
var processor = method.Body.GetILProcessor();
var methodBodyFirstInstruction = method.Body.Instructions.First();
if (method.IsConstructor && method.Body.Instructions.Any(i => i.OpCode == OpCodes.Call)) {
methodBodyFirstInstruction = method.Body.Instructions.First(i => i.OpCode == OpCodes.Call).Next;
}
var initAttributeVariable = this.GetAttributeInstanceInstructions(processor,
attribute,
method,
attributeVariableDefinition,
methodVariableDefinition);
IEnumerable<Instruction> callInitInstructions = null,
createParametersArrayInstructions = null;
if (null != initMethodRef) {
createParametersArrayInstructions = CreateParametersArrayInstructions(
processor,
method,
parameterTypeRef,
parametersVariableDefinition);
callInitInstructions = GetCallInitInstructions(
processor,
type,
method,
attributeVariableDefinition,
methodVariableDefinition,
parametersVariableDefinition,
initMethodRef);
}
var callOnEntryInstructions = GetCallOnEntryInstructions(processor, attributeVariableDefinition, onEntryMethodRef);
var saveRetvalInstructions = GetSaveRetvalInstructions(processor, retvalVariableDefinition);
var callOnExitInstructions = GetCallOnExitInstructions(processor, attributeVariableDefinition, onExitMethodRef);
var methodBodyReturnInstructions = GetMethodBodyReturnInstructions(processor, retvalVariableDefinition);
var methodBodyReturnInstruction = methodBodyReturnInstructions.First();
var tryCatchLeaveInstructions = GetTryCatchLeaveInstructions(processor, methodBodyReturnInstruction);
var catchHandlerInstructions = GetCatchHandlerInstructions(processor, attributeVariableDefinition, exceptionVariableDefinition, onExceptionMethodRef);
ReplaceRetInstructions(processor, saveRetvalInstructions.Concat(callOnExitInstructions).First());
processor.InsertBefore(methodBodyFirstInstruction, initAttributeVariable);
if (null != initMethodRef) {
processor.InsertBefore(methodBodyFirstInstruction, createParametersArrayInstructions);
processor.InsertBefore(methodBodyFirstInstruction, callInitInstructions);
}
processor.InsertBefore(methodBodyFirstInstruction, callOnEntryInstructions);
processor.InsertAfter(method.Body.Instructions.Last(), methodBodyReturnInstructions);
processor.InsertBefore(methodBodyReturnInstruction, saveRetvalInstructions);
if (null != taskContinuationMethodRef) {
var taskContinuationInstructions = GetTaskContinuationInstructions(
processor,
retvalVariableDefinition,
attributeVariableDefinition,
taskContinuationMethodRef);
processor.InsertBefore(methodBodyReturnInstruction, taskContinuationInstructions);
}
processor.InsertBefore(methodBodyReturnInstruction, callOnExitInstructions);
processor.InsertBefore(methodBodyReturnInstruction, tryCatchLeaveInstructions);
processor.InsertBefore(methodBodyReturnInstruction, catchHandlerInstructions);
method.Body.ExceptionHandlers.Add(new ExceptionHandler(ExceptionHandlerType.Catch) {
CatchType = exceptionTypeRef,
TryStart = methodBodyFirstInstruction,
TryEnd = tryCatchLeaveInstructions.Last().Next,
HandlerStart = catchHandlerInstructions.First(),
HandlerEnd = catchHandlerInstructions.Last().Next
});
}