面向切面的PostSharp

PostSharp 是一个令人兴奋的项目,他结合了 MSBuild Task 和 MSIL Injection 技术,从另外一个角度实现 AOP 编程。试用过后你会感觉到其便利性,我们和以往基于 Dynamic Proxy 方式的 AOP 解决方案做个比较。

  • 由于采用 MSIL Injection,因此静态代码注入的执行效率要高于使用 Reflection Emit。
  • 使用 MSBuild Task,使得开发人员可以像使用编译器内置 Attribute 那样使用 AOP。
  • 可以拦截任意方法,而 Dynamic Proxy 方式的 AOP 往往采取继承方式来拦截 Virtual 方法。
  • 拥有更多的控制权。包括中断执行流程,修改参数和返回值等等。
  • 还可以拦截 Field Access、Exception 等操作。
  • 无需将对象创建代码改成 "new proxy()",更加透明。
  • 可以使用通配符进行多重拦截匹配。
  • 静态注入带来的问题更多的是注入代码的质量和调试复杂度。

我们写一个简单的例子,看看效果。

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using PostSharp.Laos;

[Serializable]
public class AopMethodAttribute:OnMethodBoundaryAspect
{
publicoverridevoidOnEntry(MethodExecutionEventArgseventArgs)
{
//获取方法名称
Console.WriteLine("OnEntry:{0}.{1}",eventArgs.Method.ReflectedType,eventArgs.Method);

//显示方法参数
ParameterInfo[]ps=eventArgs.Method.GetParameters();
object[]pv=eventArgs.GetArguments();

for(inti=0;i<ps.Length;i++)
{
Console.WriteLine(
"{0}={1}",ps[i].Name,pv[i]);
}

}


publicoverridevoidOnExit(MethodExecutionEventArgseventArgs)
{
Console.WriteLine(
"OnExit");
}

}


public class MyClass
{
[AopMethod]
publicintTest(inti)
{
Console.WriteLine(
"Test:{0}",i);
returni++;
}

}


MyClasso
= new MyClass();
o.Test(
123 );


输出:
OnEntry:MyClass.Int32 Test(Int32)
i=123
Test:123
OnExit...

整个过程非常简单:
1. 创建一个继承自 OnMethodBoundaryAspect 的特性类,用于拦截方法。
2. override 特定的方法,执行拦截操作。方法参数提供了各种操作能力。
3. 向目标方法添加特性。
4. 编译,执行。

或许你会好奇,AopMethodAttribute 是如何被创建实例,并被执行的呢?

1. 注意编译时 VS2005 Output 窗口的输出内容,你会看到如下内容。其实 PostSharp 提供了一个 MSBuild Task,在我们每次编译时会调用它执行一些注入操作。

PostSharp 1.0 [1.0.4.162] - Copyright (c) Gael Fraiteur and Community, 2006.


2. 用反编译工具看看注入后的方法内容。看完这些代码,就算我不说,你也能明白它是如何实现拦截的了。

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> static MyClass()
{
if(!~PostSharp~Laos~Implementation.initialized)
{
thrownewLaosNotInitializedException();
}

~PostSharp~Laos~Implementation.~targetMethod~1=methodof(MyClass.Test);
~PostSharp~Laos~Implementation.~aspect~1.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~1);
}


public int Test( int i)
{
intreturnValue;
MethodExecutionEventArgseventArgs;
try
{
object[]arguments=newobject[]{i};
eventArgs
=newMethodExecutionEventArgs(methodof(MyClass.Test,MyClass),this,arguments);
~PostSharp~Laos~Implementation.~aspect~1.OnEntry(eventArgs);
if(eventArgs.FlowBehavior==FlowBehavior.Return)
{
return(int)eventArgs.ReturnValue;
}

Console.WriteLine(
"Test:{0}",i);
intnum=i++;
returnValue
=num;
eventArgs.ReturnValue
=returnValue;
~PostSharp~Laos~Implementation.~aspect~1.OnSuccess(eventArgs);
returnValue
=(int)eventArgs.ReturnValue;
}

catch(Exceptionexception)
{
eventArgs.Exception
=exception;
~PostSharp~Laos~Implementation.~aspect~1.OnException(eventArgs);
switch(eventArgs.FlowBehavior)
{
caseFlowBehavior.Continue:
returnreturnValue;

caseFlowBehavior.Return:
return(int)eventArgs.ReturnValue;
}

throw;
}

finally
{
eventArgs.ReturnValue
=returnValue;
~PostSharp~Laos~Implementation.~aspect~1.OnExit(eventArgs);
returnValue
=(int)eventArgs.ReturnValue;
}

returnreturnValue;
}

我们可以使用通配符拦截更多的内容,以简化我们的编码。

[AopMethod(AttributeTargetMembers="T*")]
public class MyClass
{
public int T1(int i)
{
Console.WriteLine("T1:{0}", i);
return i++;
}

public void T2(string s)
{
Console.WriteLine("T2:{0}", s);
}
}


我们继续写一点其它的例子,诸如拦截属性访问和异常。

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> FieldAspect
[Serializable]
public class AopPropertyAttribute:OnFieldAccessAspect
{
public override void OnGetValue(FieldAccessEventArgseventArgs)
{
Console.WriteLine(
" ExposedFieldValue:{0};StoredFieldValue:{1} " ,
eventArgs.ExposedFieldValue,eventArgs.StoredFieldValue);
}

public override void OnSetValue(FieldAccessEventArgseventArgs)
{
Console.WriteLine(
" ExposedFieldValue:{0};StoredFieldValue:{1} " ,
eventArgs.ExposedFieldValue,eventArgs.StoredFieldValue);
}
}

public class MyClass
{
[AopProperty]
private int x;

public int X
{
get { return x;}
set {x = value;}
}
}

ExceptionAspect
[Serializable]
public class AopExceptionAttribute:OnExceptionAspect
{
public override void OnException(MethodExecutionEventArgseventArgs)
{
Console.WriteLine(eventArgs.Exception.Message);
eventArgs.FlowBehavior
= FlowBehavior.Return;
}
}

public class MyClass
{
[AopException]
public void Test( int i)
{
throw new Exception( " Error " );
}
}

更详细的信息,请访问PostSharp 网站,或者查阅其帮助文件。

结论:

1.方法执行的日志记录可以用AOP实现

2.表之间的级联删除可以用AOP实现

3.数据库操作日志可以用AOP记录(因为数据库提供商不提供它的日志,导致第三方数据库同步无法便利实现)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值