예제 #1
0
파일: SorvyAop.cs 프로젝트: xyz91/SorvyAop
        private static MethodDefinition EditMethod(MethodDefinition method, List <CustomAttribute> atts)
        {
            if (null == method || null == atts || atts.Count == 0)
            {
                return(null);
            }
            atts = atts.Distinct().ToList();
            ILProcessor      il        = method.Body.GetILProcessor();
            MethodDefinition newmethod = method.Clone();

            method.Body.Instructions.Clear();
            atts.ForEach(a => method.CustomAttributes.Remove(a));
            if (!method.IsConstructor)
            {
                method.Body.Variables.Clear();
                method.Body.ExceptionHandlers.Clear();
            }
            var methbase = new VariableDefinition(method.Module.ImportReference(typeof(ExceEventArg)));

            method.Body.Variables.Add(methbase);

            var exception = new VariableDefinition(method.Module.ImportReference(typeof(System.Exception)));

            method.Body.Variables.Add(exception);

            var ps = new VariableDefinition(method.Module.ImportReference(typeof(List <object>)));

            method.Body.Variables.Add(ps);

            VariableDefinition returnvalue = null;

            var returnvoid = method.ReturnType.FullName == "System.Void";

            if (!returnvoid)
            {
                returnvalue = new VariableDefinition(method.Module.ImportReference(method.ReturnType));
                method.Body.Variables.Add(returnvalue);
            }

            var curmethod = method.Module.ImportReference(typeof(MethodBase).GetMethod("GetCurrentMethod"));

            il.AppendArr(new[] {
                il.Create(OpCodes.Newobj, method.Module.ImportReference(typeof(ExceEventArg).GetConstructor(new Type[] { }))),
                il.Create(OpCodes.Stloc_S, methbase),
                il.Create(OpCodes.Ldloc_S, methbase),
                il.Create(OpCodes.Call, curmethod),
                il.Create(OpCodes.Callvirt, method.Module.CreateMethod <ExceEventArg>("set_methodBase", typeof(MethodBase))),
            });

            if (method.Parameters.Count > 0)
            {
                il.AppendArr(new[] {
                    il.Create(OpCodes.Newobj, method.Module.ImportReference(typeof(List <object>).GetConstructor(new Type[] { }))),
                    il.Create(OpCodes.Stloc_S, ps),
                });
                foreach (var p in method.Parameters)
                {
                    il.Append(il.Create(OpCodes.Ldloc_S, ps));
                    il.Append(il.Create(OpCodes.Ldarg_S, p));
                    il.Append(il.Create(OpCodes.Box, method.Module.ImportReference(p.ParameterType)));
                    il.Append(il.Create(OpCodes.Call, method.Module.CreateMethod <List <object> >("Add", typeof(object))));
                }

                il.AppendArr(new[] {
                    il.Create(OpCodes.Ldloc_S, methbase),
                    il.Create(OpCodes.Ldloc_S, ps),
                    il.Create(OpCodes.Callvirt, method.Module.CreateMethod <ExceEventArg>("set_parameters", typeof(List <object>))),
                });
            }

            List <TypeDefinition>     typeDefinitions = new List <TypeDefinition>();
            List <VariableDefinition> variables       = new List <VariableDefinition>();
            Dictionary <CustomAttribute, Dictionary <string, Instruction> > excehandler = new Dictionary <CustomAttribute, Dictionary <string, Instruction> >();

            for (int i = 0; i < atts.Count(); i++)
            {
                var excedic = new Dictionary <string, Instruction>
                {
                    { "TryStart", il.Create(OpCodes.Nop) },
                    { "TryEnd", il.Create(OpCodes.Stloc_S, exception) },
                    { "HandlerStart", il.Create(OpCodes.Nop) },
                    { "HandlerEnd", il.Create(OpCodes.Nop) }
                };
                excehandler.Add(atts[i], excedic);
                var w = new ExceptionHandler(ExceptionHandlerType.Catch)
                {
                    CatchType    = method.Module.ImportReference(typeof(Exception)),
                    TryStart     = excehandler[atts[i]]["TryStart"],
                    TryEnd       = excehandler[atts[i]]["TryEnd"],
                    HandlerStart = excehandler[atts[i]]["TryEnd"],
                    HandlerEnd   = excehandler[atts[i]]["HandlerEnd"]
                };
                method.Body.ExceptionHandlers.Add(w);
                TypeDefinition re = atts[i].AttributeType.Resolve();
                typeDefinitions.Add(re);
                var begin = SearchMethod(re, "Before");

                var log = new VariableDefinition(method.Module.ImportReference(atts[i].AttributeType));
                method.Body.Variables.Add(log);
                variables.Add(log);
                il.AppendArr(new[] {
                    il.Create(OpCodes.Newobj, atts[i].Constructor),
                    il.Create(OpCodes.Stloc_S, log),
                });
                if (begin != null)
                {
                    il.AppendArr(new[] {
                        il.Create(OpCodes.Ldloc_S, log),
                        il.Create(OpCodes.Ldloc_S, methbase),
                        il.Create(OpCodes.Call, begin),
                    });
                }
            }
            for (int i = atts.Count - 1; i >= 0; i--)
            {
                il.Append(excehandler[atts[i]]["TryStart"]);
            }
            if (method.IsConstructor)
            {
                newmethod.Body.Instructions.RemoveAt(newmethod.Body.Instructions.Count - 1);
                il.AppendArr(newmethod.Body.Instructions.ToArray());
            }
            else
            {
                if (!method.IsStatic)
                {
                    il.Append(il.Create(OpCodes.Ldarg_0));
                }
                foreach (var p in method.Parameters)
                {
                    il.Append(il.Create(OpCodes.Ldarg_S, p));
                }
                il.Append(il.Create(OpCodes.Call, newmethod));
            }
            if (!returnvoid)
            {
                il.AppendArr(new[] {
                    il.Create(OpCodes.Stloc_S, returnvalue),
                    il.Create(OpCodes.Ldloc_S, methbase),
                    il.Create(OpCodes.Ldloc_S, returnvalue),
                    il.Create(OpCodes.Box, method.Module.ImportReference(method.ReturnType)),
                    il.Create(OpCodes.Callvirt, method.Module.CreateMethod <ExceEventArg>("set_returnValue", method.ReturnType.GetType())),
                });
            }
            for (int i = 0; i < atts.Count(); i++)
            {
                var exce = SearchMethod(typeDefinitions[i], "Exception");
                il.AppendArr(new[] {
                    il.Create(OpCodes.Leave_S, excehandler[atts[i]]["HandlerEnd"]),
                    excehandler[atts[i]]["TryEnd"],
                    il.Create(OpCodes.Nop),

                    il.Create(OpCodes.Ldloc_S, methbase),
                    il.Create(OpCodes.Ldloc_S, exception),

                    il.Create(OpCodes.Callvirt, method.Module.CreateMethod <ExceEventArg>("set_exception", typeof(Exception))),

                    il.Create(OpCodes.Ldloc_S, variables[i]),
                    il.Create(OpCodes.Ldloc_S, methbase),
                    il.Create(OpCodes.Call, exce),

                    il.Create(OpCodes.Nop),
                    il.Create(OpCodes.Leave_S, excehandler[atts[i]]["HandlerEnd"]),
                    excehandler[atts[i]]["HandlerEnd"],
                });

                var after = SearchMethod(typeDefinitions[i], "After");

                if (after != null)
                {
                    il.AppendArr(new[] {
                        il.Create(OpCodes.Ldloc_S, variables[i]),
                        il.Create(OpCodes.Ldloc_S, methbase),
                        il.Create(OpCodes.Call, after),
                    });
                }
            }
            if (!returnvoid)
            {
                il.Append(il.Create(OpCodes.Ldloc_S, returnvalue));
            }
            il.Append(il.Create(OpCodes.Ret));
            if (method.IsConstructor)
            {
                return(null);
            }
            return(newmethod);
        }