C#利用Attribute实现简易AOP介绍

时间:2021-11-28 23:56:15

首先看一段简单的代码:

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//来自UI层的调用
private void button1_Click(object sender, EventArgs e)
{
BusinessHandler handler = new BusinessHandler();
handler.DoSomething();
}
}
//业务层的类和方法
public class BusinessHandler
{
public void DoSomething()
{
MessageBox.Show("执行了方法本身!");
}
}

那么假设这是一个web程序,我们想在按钮点击时,先校验session,然后检验权限、起事务、写日志,然后再执行操作本身,最后再写日志。显然不能把对上面这些操作的方法调用都写在DoSomething()里,这样代码会变成一大坨屎,那我们该怎么办呢?

所谓AOP(面向切面编程)这个唬人的名词就是干这件事用的,其实现方式有很多种,比如利用Spring等框架,但是在实际项目中并不是想引一个框架进来就能随便引的,很多时候都需要我们自己手写一些机制。

这里想到了MVC当中的Filter,只要在Controller或者Action上打一个特性标签(Attribute),就能在方法执行前后做一些其他事情了。那么我们就来简单模拟一个Filter的实现吧。

首先给原先的方法改造一下,改成特性标签这种优雅的方式:

 
//业务层的类和方法,让它继承自上下文绑定类的基类
[MyInterceptor]
public class BusinessHandler : ContextBoundObject
{
[MyInterceptorMethod]
public void DoSomething()
{
MessageBox.Show("执行了方法本身!");
}
}

有了特性标签自然就要有特性标签对应的类,以及AOP的实现方法,这些东西可以单独独立到一个文件或程序集里。

首先是贴在方法上的标签,实现为空:

 
//贴在方法上的标签
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public sealed class MyInterceptorMethodAttribute : Attribute { }

之后定义贴在类上的标签:

 
//贴在类上的标签
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class MyInterceptorAttribute : ContextAttribute, IContributeObjectSink
{
public MyInterceptorAttribute()
: base("MyInterceptor")
{ }
//实现IContributeObjectSink接口当中的消息接收器接口
public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink next)
{
return new MyAopHandler(next);
}
}

这里定义了一个MyAopHandler类,实现如下:

 
//AOP方法处理类,实现了IMessageSink接口,以便返回给IContributeObjectSink接口的GetObjectSink方法
public sealed class MyAopHandler : IMessageSink
{
//下一个接收器
private IMessageSink nextSink;
public IMessageSink NextSink
{
get { return nextSink; }
}
public MyAopHandler(IMessageSink nextSink)
{
this.nextSink = nextSink;
}
//同步处理方法
public IMessage SyncProcessMessage(IMessage msg)
{
IMessage retMsg = null;
//方法调用消息接口
IMethodCallMessage call = msg as IMethodCallMessage;
//如果被调用的方法没打MyInterceptorMethodAttribute标签
if (call == null || (Attribute.GetCustomAttribute(call.MethodBase, typeof(MyInterceptorMethodAttribute))) == null)
{
retMsg = nextSink.SyncProcessMessage(msg);
}
//如果打了MyInterceptorMethodAttribute标签
else
{
MessageBox.Show("执行之前");
retMsg = nextSink.SyncProcessMessage(msg);
MessageBox.Show("执行之后");
}
return retMsg;
}
//异步处理方法(不需要)
public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
{
return null;
}
}

注意到上面的执行前后具体操作部分代码,相当于一个“代理类”,它实质上是改变了方法执行的上下文。可以用委托等面向对象程序结构把具体实现暴露给外部进行二次开发。