使用PostSharp实现AOP编程
一、AOP(Aspect Oriented Programming):面向切面编程,将业务中的公共部分提取出来统一实现,而不必到处重复编写,体现了DRY原则。
用武之地:性能分析、日志打印、异常捕获、事务处理等。
二、由于工作需要,希望对程序中的核心方法做日志跟踪:方法开始执行时,方法参数值是什么,执行时间等
方案一:在这些方法的开始和结束部分编写记录日志
该方案存在代码重复性问题:即要在每个方法内编写重复代码,能否将这种重复的方法提取出来,减少对方法的侵入?答案是AOP。
方案二:运用AOP思想,本文选择使用PostSharp实现
三、PostSharp 2.0及以上版本分为社区版和商业版,社区版只有少部分功能是可以免费使用的,但已经满足基本需求,故采用PostSharp社区版
从PostSharp官网看到社区版和商业版的区别,可以发现哪些特性是能免费使用,请根据实际情况判断是否符合自己项目的需要!

本文使用开发工具及环境为VS2019,.net framework 4.0,PostSharp-6.8.7.exe
1、首先下载并安装PostSharp(从PostSharp官网下载社区版)
2、使用Nuget,安装PostSharp包依赖
3、创建日志跟踪特性:LogTraceAttribute
该特性类继承在PostSharp特性类:OnMethodBoundaryAspect
4、重写下面两个方法:
(1)OnEntry方法:进入方法后执行
public override void OnEntry(MethodExecutionArgs args)
{}
(2)OnExit方法:方法执行完执行
public override void OnExit(MethodExecutionArgs args)
{}
LogTraceAttribute类完整代码如下:
[Serializable] [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] class LogTraceAttribute : OnMethodBoundaryAspect { public override void OnEntry(MethodExecutionArgs args) { var parameters = args.Method.GetParameters(); var printInfo = $"方法:{args.Method.Name},开始执行,时间:{DateTime.Now}"; Trace.TraceInformation(printInfo); } public override void OnExit(MethodExecutionArgs args) { var printInfo = $"方法:{args.Method.Name},结束执行,时间:{DateTime.Now}"; Trace.TraceInformation(printInfo); } }
5、假设有一个通信类:Communication,该类有如下方法:
(1)Send():用于发送数据
(2)Receive():用于接收数据
现在希望这两个方法开始执行和执行结束后能记录执行时间,则这两个方法应用LogTrace特性即可,Communication完整代码如下:
class Communication { [LogTrace] public void Send() { Trace.TraceInformation("发送数据……"); } [LogTrace] public void Receive() { Trace.TraceInformation("接收数据……"); } }
6、Main方法中编写如下代码:
static void Main(string[] args) { var communication = new Communication(); communication.Send(); System.Threading.Thread.Sleep(2000); communication.Receive(); Console.ReadKey(); }
7、执行程序,在输出窗口显示如下输出信息:
PostSharpSample.exe Information: 0 : 方法:Send,开始执行,时间:2021/1/24 22:30:47 PostSharpSample.exe Information: 0 : 发送数据…… PostSharpSample.exe Information: 0 : 方法:Send,结束执行,时间:2021/1/24 22:30:48 PostSharpSample.exe Information: 0 : 方法:Receive,开始执行,时间:2021/1/24 22:30:50 PostSharpSample.exe Information: 0 : 接收数据…… PostSharpSample.exe Information: 0 : 方法:Receive,结束执行,时间:2021/1/24 22:30:50
通过输出信息,可以看到LogTrace特性的OnEntry、OnExit方法将Send方法包裹起来。Receive方法也是如此。
8、使用反编译工具dnSpy查看Communication类:
internal class Communication { // Token: 0x06000001 RID: 1 RVA: 0x00002050 File Offset: 0x00000250 public void Send() { MethodExecutionArgs methodExecutionArgs = new MethodExecutionArgs(null, null); MethodExecutionArgs methodExecutionArgs2 = methodExecutionArgs; MethodBase <<EMPTY_NAME>> = <>z__a_1._3; methodExecutionArgs2.Method = <<EMPTY_NAME>>; <>z__a_1.a0.OnEntry(methodExecutionArgs); try { Trace.TraceInformation("发送数据……"); } finally { <>z__a_1.a0.OnExit(methodExecutionArgs); } } // Token: 0x06000002 RID: 2 RVA: 0x000020AC File Offset: 0x000002AC public void Receive() { MethodExecutionArgs methodExecutionArgs = new MethodExecutionArgs(null, null); MethodExecutionArgs methodExecutionArgs2 = methodExecutionArgs; MethodBase <<EMPTY_NAME>> = <>z__a_1._4; methodExecutionArgs2.Method = <<EMPTY_NAME>>; <>z__a_1.a1.OnEntry(methodExecutionArgs); try { Trace.TraceInformation("处理接收数据……"); } finally { <>z__a_1.a1.OnExit(methodExecutionArgs); } } }
红色部分代码是PostSharp注入到程序集中的代码,将方法内容包裹起来,与输出跟踪信息一致。
9、总结:PostSharp使用特性实现对方法的非侵入管理,代码看起来简洁优雅。
浙公网安备 33010602011771号