您的位置:首页 > 其它

使用动态代理,提高工作效率

2008-05-21 17:42 295 查看
动态代理的一个最主要的应用场合就是实现AOP - 截获方法调用,加入自己的预处理、后处理或Around处理。

我在ESBasic.Emit中实现了对这些截获的支持。

首先,介绍两个截获者:

/// <summary>

/// IMethodInterceptor 对方法进行截获并加入预处理和后处理。

/// </summary>

public interface IMethodInterceptor

{

void PreProcess(InterceptedMethod method);

void PostProcess(InterceptedMethod method ,object returnVal);

}
IMethodInterceptor 很容易理解,用于为截获插入预处理、后处理。这个非常容易理解。

/// <summary>

/// IAroundInterceptor 对方法进行Around截获处理。注意,必须要触发目标方法的调用。

/// </summary>

public interface IAroundInterceptor

{

object AroundCall(InterceptedMethod method);

}

Around处理由IAroundInterceptor完成。什么是Around处理了?比如,我们想捕获目标方法的异常,需要使用TryCatch将目标方法Around起来,这就是Around处理的一个例子。

在上面的接口方法中都有一个参数InterceptedMethod,它封装了被截获的目标方法的基本信息。

public sealed class InterceptedMethod

{

#region Ctor

public InterceptedMethod() { }

public InterceptedMethod(object _target, MethodInfo _method, object[] paras)

{

this.target = _target;

this.method = _method;

this.arguments = paras;

}

#endregion

#region Method

private MethodInfo method;

/// <summary>

/// Method 被截获的目标方法

/// </summary>

public MethodInfo Method

{

get { return method; }

set { method = value; }

}

#endregion

#region Target

private object target;

/// <summary>

/// Target 被截获的方法需要在哪个对象上调用。

/// </summary>

public object Target

{

get { return target; }

set { target = value; }

}

#endregion

#region Arguments

private object[] arguments;

/// <summary>

/// Arguments 调用被截获的方法的参数

/// </summary>

public object[] Arguments

{

get { return arguments; }

set { arguments = value; }

}

#endregion

#region Invoke

/// <summary>

/// Invoke 执行目标方法

/// </summary>

public object Invoke()

{

return this.method.Invoke(this.target, this.arguments);

}

#endregion

}

好,如何使用ESBasic.Emit来创建动态代理了?很简单,你只需要调用

public static TInterface CreateAopProxy<TInterface>(object origin, IMethodInterceptor methodInterceptor, IAroundInterceptor aroundInterceptor)
如果不需要某种截获处理,对应的参数传入null即可。

举个例子,我们需要使用动态代理截获IComputer所有方法调用抛出的异常,并记录日志。IComputer定义如下:

public interface IComputer

{

int Add(int a, int b);

}

public class Computer : IComputer

{

public int Add(int a, int b)

{

throw new Exception("TestException");

return a + b;

}

}
我可以使用Around截获者来截获异常,所以我实现一个自己的IAroundInterceptor:

public class ExceprionAroundInterceptor : IAroundInterceptor

{

#region IAroundInterceptor 成员

public object AroundCall(InterceptedMethod method)

{

try

{

return method.Invoke();

}

catch (Exception ee)

{

ee = ee;

//.. log Exception

throw;

}

}

#endregion

}
现在,我们可以这样获得针对IComputer的动态代理的引用:

IComputer proxy = ESBasic.Emit.Application.DynamicProxyFactory.CreateAopProxy<IComputer>(new Computer() ,null ,new ExceprionAroundInterceptor()) ;

proxy.Add(1, 2);
这样就ok了,Add方法抛出的异常会被ExceprionAroundInterceptor截获。

最后,提醒一下,如果你让Computer不从IComputer继承,运行结果也一样。你应该已经看到DynamicProxyFactory.CreateAopProxy方法的第一个参数是object类型,而不是泛型T,这说明只要对应的object包含了和目标接口一样的方法(签名完全一致)就可以 -- 这就是所谓的“换脸”能力,可以在这里看到更详细的说明。

由于动态代理是使用Emit发射实现,所以效率上来说,和你手写的代码是没有区别的。

下载 ESBasic.Emit.dll。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: