MethodDecorator.Fody.MethodDecorator.Decorate C# (CSharp) Method

Decorate() public method

public Decorate ( Mono.Cecil.TypeDefinition type, Mono.Cecil.MethodDefinition method, CustomAttribute attribute ) : void
type Mono.Cecil.TypeDefinition
method Mono.Cecil.MethodDefinition
attribute CustomAttribute
return void
        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
            });
        }

Usage Example

    private void DecorateByType(MethodDecorator.Fody.MethodDecorator decorator)
    {
        var referenceFinder       = new ReferenceFinder(this.ModuleDefinition);
        var markerTypeDefinitions = this.FindMarkerTypes();

        // Look for rules in the assembly and module.
        var assemblyRules = FindAspectRules(this.ModuleDefinition.Assembly.CustomAttributes);
        var moduleRules   = FindAspectRules(this.ModuleDefinition.CustomAttributes);

        // Read the top-level and nested types from this module
        foreach (var type in this.ModuleDefinition.Types.SelectMany(x => GetAllTypes(x)))
        {
            // Look for rules on the type and marker attributes
            var classRules = FindByMarkerType(markerTypeDefinitions, type.CustomAttributes)
                             .Concat(FindAspectRules(type.CustomAttributes, true));

            // Loop through all methods in this type
            foreach (var method in type.Methods.Where(x => x.HasBody))
            {
                // Find any rules applied to the method.
                var methodRules = FindByMarkerType(markerTypeDefinitions, method.CustomAttributes)
                                  .Concat(FindAspectRules(method.CustomAttributes, true));

                // Join together all the rules and give them an ordering number starting at 0 for
                // the highest level (assembly) to N as a lowest level (last attribute on the method)
                var allRules = assemblyRules
                               .Concat(moduleRules)
                               .Concat(classRules)
                               .Concat(methodRules)
                               .Select((Rule, ScopeOrdering) => new { Rule, ScopeOrdering });

                // Group the rules by the aspect type
                foreach (var aspectSet in
                         allRules.ToLookup(x => x.Rule.MethodDecoratorAttribute.AttributeType))
                {
                    // Sort the rules in priority order (so that attributes applied to the
                    // method take precedence over the type, module then assembly)
                    // Then pick out the first rule - this tells us whether to include
                    // or exclude.
                    var ruleList = aspectSet
                                   .Where(x => x.Rule.Match(type, method))
                                   .OrderBy(x => x.Rule.AttributePriority)              // Apply lowest priority number first
                                   .ThenByDescending(x => x.ScopeOrdering)              // Method rules sort 1st
                                   .Select(x => x.Rule);

                    var rule = ruleList.FirstOrDefault();

                    // If we have a rule and it isn't an exclusion, apply the method decoration.
                    if (rule != null && !rule.AttributeExclude)
                    {
                        decorator.Decorate(
                            type,
                            method,
                            rule.MethodDecoratorAttribute);
                    }
                }
            }
        }
    }
All Usage Examples Of MethodDecorator.Fody.MethodDecorator::Decorate