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

时间:2022-05-10 08:48:34
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/

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

  1. ASP&period;NET MVC中的cshtml页面中的下拉框的使用

    ASP.NET MVC中的cshtml页面中的下拉框的使用 用上@Html.DropDownList 先记下来..以做备忘...

  2. EF&plus;LINQ事物处理 C&num; 使用NLog记录日志入门操作 ASP&period;NET MVC多语言 仿微软网站效果&lpar;转&rpar; 详解C&num;特性和反射(一) c&num; API接受图片文件以Base64格式上传图片 &period;NET读取json数据并绑定到对象

    EF+LINQ事物处理   在使用EF的情况下,怎么进行事务的处理,来减少数据操作时的失误,比如重复插入数据等等这些问题,这都是经常会遇到的一些问题 但是如果是我有多个站点,然后存在同类型的角色去操作 ...

  3. asp&period;net MVC 应用程序的生命周期(下)

    看看上面的UrlRoutingModule源码里面是怎么实现Init方法的,Init()方法里面我标注红色的地方: application.PostResolveRequestCache += new ...

  4. 【转】asp&period;net mvc(模式)和三层架构(BLL、DAL、Model)的联系与区别

    原文地址:http://blog.csdn.net/luoyeyu1989/article/details/8275866 首先,MVC和三层架构,是不一样的. 三层架构中,DAL(数据访问层).BL ...

  5. asp&period;net mvc(模式)和三层架构(BLL、DAL、Model)的联系与区别 转载自:http&colon;&sol;&sol;blog&period;csdn&period;net&sol;luoyeyu1989&sol;article&sol;details&sol;8275866

    首先,MVC和三层架构,是不一样的. 三层架构中,DAL(数据访问层).BLL(业务逻辑层).WEB层各司其职,意在职责分离. MVC是 Model-View-Controller,严格说这三个加起来 ...

  6. asp&period;net mvc 之旅—— 第二站 窥探Controller下的各种Result

    平时我们在Action中编码的时候,我们都知道所有的Action返回值类型都是ActionResult,并且我们的返回值也是各种奇葩,比如:Json(),Content(), View()等等...当 ...

  7. asp&period;net MVC实现文章的上一篇下一篇

    由于这个东西的原理没有什么难的(只是实现的时候有少量的坑),故直接上代码以便查阅.另:本文给出的Action附送了点击量统计. public ActionResult SingleNews(int? ...

  8. asp&period;net MVC实现文章的&OpenCurlyDoubleQuote;上一篇下一篇”

    由于这个东西的原理没有什么难的(只是实现的时候有少量的坑),故直接上代码以便查阅.另:本文给出的Action附送了点击量统计. public ActionResult SingleNews(int? ...

  9. 如何建立一个完整的游戏AI

    http://blog.friskit.me/2012/04/how-to-build-a-perfect-game-ai/ 人工智能(Artificial Intelligence)在游戏中使用已经 ...

随机推荐

  1. mysql5&period;5手册读书日记&lpar;2&rpar;

    <?php /* * * MySQL_5.5中文参考手册 485开始 * * mysql> SELECT CASE 1 WHEN 1 THEN 'one' -> WHEN 2 THE ...

  2. C&num; 只启动一个实例完全解决方案

    工作上经常会遇到"程序只能启动一个实例"这样的需求. 我想,这样的需求应该很普遍,所以没打算去动脑筋,去找谷歌问下就得了,用下来发现,不是这里不爽就是那里不行. 先说下我详细的几点 ...

  3. 【jQuery基础学习】02 jQuery的DOM操作

    DOM操作分为3个方面: DOM Core    任何一种支持DOM Core的语言都可以使用它,比如getElementById就是DOM Core操作 HTML-DOM  只能用来处理web文档 ...

  4. javascript循环

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  5. 51nod:1689 逛街

    原题链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1689 一开始想枚举逛街的终点,然后开两个大根堆维护b值,分别 ...

  6. dedecms系统后台登陆提示用户名密码不存在

    dedecms最近被曝有非常多的安全漏洞,最近有些用户反应后台管理员账号密码没有修改但无法正常登陆,提示用户名不存在,经研究发现是程序漏洞管理员被直接篡改,解决方案如下. 工具/原料 dedecms ...

  7. ASP&period;NET Core的身份认证框架IdentityServer4--&lpar;2&rpar;API跟WEB端配置

    API配置 可以使用ASP.NET Core Web API模板.同样,我们建议您控制端口并使用与之前一样的方法来配置Kestrel和启动配置文件.端口配置为http://localhost:5001 ...

  8. JavaScript实现本地图片上传前进行裁剪预览

    本项目支持IE8+,测试环境IE8,IE9,IE10,IE11,Chrome,FireFox测试通过 另:本项目并不支持Vue,React等,也不建议,引入JQuery和Vue.React本身提倡的开 ...

  9. fullScreen&period;html

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...

  10. sql的行转列&lpar;PIVOT&rpar;与列转行&lpar;UNPIVOT&rpar; webapi 跨域问题 Dapper 链式查询 扩展 T4 代码生成 Demo &lpar;抽奖程序&rpar;

    sql的行转列(PIVOT)与列转行(UNPIVOT)   在做数据统计的时候,行转列,列转行是经常碰到的问题.case when方式太麻烦了,而且可扩展性不强,可以使用 PIVOT,UNPIVOT比 ...