首页 新闻 会员 周边

高难度问题求大神帮忙!C#用特性捕捉方法的异常,在线等

0
悬赏园豆:200 [已解决问题] 解决于 2013-11-28 13:37

建立一个方法的attribute,可以放在任意方法上,可以自动记录方法出错时的信息,就不用写try 。。cacth.       【注意】 不是在asp.net MVC下,是在普通三层结构下写的的特性

例子:

[AttrbuteTest]//这个特性是用来捕捉方法的异常,并记录到日志
public void Test()
{
    string str = "test";
    int i = int.Parse(str);
}

net668的主页 net668 | 初学一级 | 园豆:5
提问于:2013-11-27 10:21
< >
分享
最佳答案
0

不给我200分,我真鄙视你了.

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);
        }
    }
}
 
收获园豆:50
迅捷网络[来送福利] | 小虾三级 |园豆:576 | 2013-11-27 11:46

这个怎么用?

天地盟主 | 园豆:251 (菜鸟二级) | 2013-11-27 17:28

楼主,你写的的确很强大,但是我用了更为简结的方式,就5行代码不到就搞定了,可以参考我写的日志。。

日志地址:http://www.cnblogs.com/ChiYue/p/3447328.html

net668 | 园豆:5 (初学一级) | 2013-11-28 13:35
其他回答(9)
0

Log4.Net

鸾枫 | 园豆:202 (菜鸟二级) | 2013-11-27 10:38
0

一定要给楼上200分,这太全了...

Zery | 园豆:6151 (大侠五级) | 2013-11-27 11:56
0

楼上的楼上出了大招

一块垃圾 | 园豆:202 (菜鸟二级) | 2013-11-27 13:16
0

悲催 完全看不懂

keeppuching | 园豆:6 (初学一级) | 2013-11-27 15:06
0

楼上的大招秒杀Boss了啊!!!学习了。

祁临芯 | 园豆:251 (菜鸟二级) | 2013-11-27 15:43
1

http://www.cnblogs.com/xcj26/p/3442089.html

这个才是真的,分点来分来...

ymnets | 园豆:4 (初学一级) | 2013-11-27 16:15
0

学习了,各种强大

大芝麻 | 园豆:4 (初学一级) | 2013-11-27 23:37
0

Mark.   不过好像大神给的不是log exception, 是log method的执行情况

gunsmoke | 园豆:3592 (老鸟四级) | 2013-11-28 10:07
0

http://www.cnblogs.com/ChiYue/p/3447328.html

net668 | 园豆:5 (初学一级) | 2013-11-28 13:36
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册