メソッドのattributeを確立し、任意のメソッドに置くことができ、メソッドエラー時の情報を自動的に記録することができ、tryを書く必要はありません.cacth. 【注意】aspではありません.NetMVCでは、通常の3層構造で書かれている特性です.

9207 ワード

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Reflection;

using System.Reflection.Emit;



namespace ConsoleApp

{

    class Program

    {

        static void Main(string[] args)

        {

            TestA test = DynamicProxy.Create<TestA>();

            int result = test.TestMethod(1, 2);



            Console.WriteLine(result);



            Console.WriteLine("done...");

            Console.ReadLine();

        }

    }



    public class TestA

    {

        [Log]

        public virtual int TestMethod(int a, int b)

        {

            return a + b;

        }

    }



    public class AspectContext

    {

        public object[] ParameterArgs { get; set; }

    }



    public abstract class AspectAttribute : Attribute

    {

        public abstract void BeforeInvoke(AspectContext cxt);



        public abstract void AfterInvoke(AspectContext cxt);

    }



    public class LogAttribute : AspectAttribute

    {

        public override void BeforeInvoke(AspectContext cxt)

        {

            if (cxt != null && cxt.ParameterArgs != null)

            {

                foreach (object item in cxt.ParameterArgs)

                    Console.WriteLine(item);

            }



            Console.WriteLine("a");

        }



        public override void AfterInvoke(AspectContext cxt)

        {

            Console.WriteLine("b");

        }

    }



    public class DynamicProxy

    {

        private static Dictionary<string, object> func_dic = new Dictionary<string, object>();



        public static T Create<T>()

        {

            return Create<T>(typeof(T));

        }



        public static T Create<T>(Type srcType)

        {

            object obj = null;

            if (!func_dic.TryGetValue(srcType.FullName, out obj))

            {

                lock (func_dic)

                {

                    if (!func_dic.TryGetValue(srcType.FullName, out obj))

                    {

                        Type type = CreateProxyType(srcType);

                        obj = CreateFunc<T>(type);

                        func_dic.Add(srcType.FullName, obj);

                    }

                }

            }



            //        

            Func<T> func = obj as Func<T>;

            if (func == null)

                throw new Exception("unknown exception");



            return func();  

        }



        //        

        private static Func<T> CreateFunc<T>(Type type)

        {

            DynamicMethod method = new DynamicMethod("", typeof(T), null);

            var il = method.GetILGenerator();



            ConstructorInfo info = type.GetConstructor(Type.EmptyTypes);

            if (info == null) return null;



            il.Emit(OpCodes.Newobj, info);

            il.Emit(OpCodes.Ret);



            return method.CreateDelegate(typeof(Func<T>)) as Func<T>;

        }



        private static Type CreateProxyType(Type srcType)

        {

            AssemblyName assemblyName = new AssemblyName(srcType.Name + "_Aop_Assmely");

            AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);

            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(srcType.Name + "_Aop_Module");



            string typeName = srcType.Name + "_Aop";

            TypeAttributes attr = TypeAttributes.Class | TypeAttributes.Public;

            TypeBuilder typeBuilder = moduleBuilder.DefineType(typeName, attr, srcType, Type.EmptyTypes);



            MethodInfo[] methods = srcType.GetMethods(BindingFlags.Public | BindingFlags.Instance);

            foreach (MethodInfo method in methods)

                OverrideMethods(typeBuilder, method);



            return typeBuilder.CreateType();

        }



        private static void OverrideMethods(TypeBuilder tb, MethodInfo method)

        {

            if (!method.IsPublic|| !method.IsVirtual || IsObjectMethod(method)) return;



            Type[] paramTypes = GetParameterTypes(method);

            MethodAttributes attr = MethodAttributes.Public | MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.Virtual;

            MethodBuilder mb = tb.DefineMethod(method.Name, attr, method.ReturnType, paramTypes);



            LocalBuilder result = null;

            ILGenerator il = mb.GetILGenerator();

            bool is_void = method.ReturnType != typeof(void);



            if (is_void == false)

                result = il.DeclareLocal(method.ReturnType);



            object[] attrs = method.GetCustomAttributes(typeof(AspectAttribute), false);

            if (attrs != null)

            {

                //              object[]

                CreateLocalParameterArr(il, paramTypes);



                //   AspectContext

                Type ctxType = typeof(AspectContext);

                ConstructorInfo info = ctxType.GetConstructor(Type.EmptyTypes);



                var ctx = il.DeclareLocal(ctxType);

                il.Emit(OpCodes.Newobj, info);

                il.Emit(OpCodes.Stloc, ctx);



                // AspectContext      ParameterArgs  

                var propMethod = ctxType.GetMethod("set_ParameterArgs");

                il.Emit(OpCodes.Ldloc, ctx);

                il.Emit(OpCodes.Ldloc_0);

                il.Emit(OpCodes.Call, propMethod);



                int m = attrs.Length;

                LocalBuilder[] lbs = new LocalBuilder[m];

                MethodInfo[] endInvokeMethods = new MethodInfo[m];



                //          ,        BeforeInvoke  

                for (int i = 0; i < m; i++)

                {

                    var tmpType = attrs[i].GetType();

                    var aspect = il.DeclareLocal(tmpType);

                    ConstructorInfo tmpInfo = tmpType.GetConstructor(Type.EmptyTypes);



                    il.Emit(OpCodes.Newobj, tmpInfo);

                    il.Emit(OpCodes.Stloc, aspect);



                    var before_invoke_method = tmpType.GetMethod("BeforeInvoke");

                    endInvokeMethods[i] = tmpType.GetMethod("AfterInvoke");



                    il.Emit(OpCodes.Ldloc, aspect);

                    il.Emit(OpCodes.Ldloc, ctx);

                    il.Emit(OpCodes.Callvirt, before_invoke_method);

                    il.Emit(OpCodes.Nop);



                    lbs[i] = aspect;

                }



                //   ,       

                for (int i = 0; i <= paramTypes.Length; i++)

                    il.Emit(OpCodes.Ldarg, i);



                //       

                il.Emit(OpCodes.Call, method);



                //      ,          

                if (is_void == false)

                    il.Emit(OpCodes.Stloc, result);



                //       AfterInvoke  

                for (int i = 0; i < m; i++)

                {

                    il.Emit(OpCodes.Ldloc, lbs[i]);

                    il.Emit(OpCodes.Ldloc, ctx);

                    il.Emit(OpCodes.Callvirt, endInvokeMethods[i]);

                    il.Emit(OpCodes.Nop);

                }



                //      ,       

                if (is_void == false)

                    il.Emit(OpCodes.Ldloc, result);



                //  

                il.Emit(OpCodes.Ret);

            }

        }



        private static void CreateLocalParameterArr(ILGenerator il, Type[] paramTypes)

        {

            il.DeclareLocal(typeof(object[]));

            il.Emit(OpCodes.Ldc_I4, paramTypes.Length);

            il.Emit(OpCodes.Newarr, typeof(object));

            il.Emit(OpCodes.Stloc_0);



            for (int i = 0; i < paramTypes.Length; i++)

            {

                il.Emit(OpCodes.Ldloc_0);

                il.Emit(OpCodes.Ldc_I4, i);

                il.Emit(OpCodes.Ldarg, i + 1);

                if (paramTypes[i].IsValueType)

                    il.Emit(OpCodes.Box, paramTypes[i]);

                il.Emit(OpCodes.Stelem_Ref);

            }

        }



        private static Type[] GetParameterTypes(MethodInfo method)

        {

            var paramInfos = method.GetParameters();

            int len = paramInfos.Length;

            Type[] paramTypes = new Type[len];

            for (int i = 0; i < len; i++)

                paramTypes[i] = paramInfos[i].ParameterType;



            return paramTypes;

        }



        //       Object    

        private static bool IsObjectMethod(MethodInfo info)

        {

            string[] arr = new string[] { "ToString", "GetType", "GetHashCode", "Equals" };

            return arr.Contains(info.Name);

        }

    }

}


例:AttrbuteTest//この特性はメソッドの異常をキャプチャし、ログpublic void Test(){string str="test";int i=int.Parse(str); 
原文出典:http://q.cnblogs.com/q/57373/