用RealProxy实现AOP
MSDN上看到篇关于用RalProxy实现AOP的文章,于是对RealProxy做了下研究
RealProxy是什么
RealProxy是Remote技术的一部分,是跨类型远程对象的透明代理,Remote技术已经逐渐被WCF代替,我也没深入研究过,因为我的工作中用不到。
实现AOP
Box有两个方法,要在这两个日期调用前和调用后加上日志,简单粗暴的方法是在代码是直接加,但如果有很多个类似的class要加,BigBox,SmallBox,SuperBox……
public class Box { void Open() { } void Close() { } }
按OOP的思想将Box抽象化,做为基类,然后使用Decorator模式来实现日志功能
public abstract class Box { public abstract void Open(); public abstract void Close(); } public class BixBox : Box { public void Open() { } public void Close { } } public class BoxDecorator { private Box box = null; public BoxDecorator(Box box) { this.box = box; } public void Open() { Console.WriteLine("Log before box open"); box.Open(); Console.WriteLine("Log after box open"); } public void Close() { Console.WriteLine("Log before box open"); box.Close(); Console.WriteLine("Log after box open"); } }
Decorator可以完成所有从Box基类派出来出的类型日志功能,但是如果不是派生自Box类呢,系统中有茫茫多的类,都要创建一个Decorator! 这还是一项庞大的代码活。
使用RealProxy实现日志功能
RealProxy的构造函数
protected RealProxy(
Type classToProxy
)
classToProxy代理的对象必需是一个抽象类(MSDN上关于RealProxy的说明:The RealProxy class is the abstract base class from which proxies must derive.)而我在代码调试中发现它必需是个interface类型才行,否刚会出现isMarshalByRef异常,的马Box抽象类要改成一个interface
public interface Box { void Open(); void Close(); }
创建AProxy代理类
public class AProxy : RealProxy { private readonly object _decorated; public AProxy(Box decorated) : base(typeof(Box)) { _decorated = decorated; } private void Log(string msg, object arg = null) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(msg, arg); Console.ResetColor(); } public override IMessage Invoke(IMessage msg) { var methodCall = msg as IMethodCallMessage; var methodInfo = methodCall.MethodBase as MethodInfo; Log("Proxy - Before executing '{0}'", methodCall.MethodName); try { var result = methodInfo.Invoke(_decorated, methodCall.InArgs); Log("Proxy - After executing '{0}' ", methodCall.MethodName); return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall); } catch (Exception e) { Log(string.Format( "Proxy- Exception {0} executing '{1}'", e), methodCall.MethodName); return new ReturnMessage(e, methodCall); } } }
AProxy必需重写RealProxy的抽象方法Invoke,可以看到invoke方法内部使用反射取到方法的名称和参数值,如果不使用RealProxy,也可以完全通过.net的反射机制来完成这个功能,RealProxy已经为我们了一个轻量框架。
使用AProxy
static void Main(string[] args) { Box bigBox = new BigBox() as Box; AProxy proxyCustomer = new AProxy(bigBox); Box myEntity = proxyCustomer.GetTransparentProxy() as Box; myEntity.Open(); myEntity.Close(); }
运行结果:
完整代码
AProxy要求一个Box类型的参数,还没有解决先前所提到的问题,AProxy依赖Box,那么将要将解偶
使用泛型类解偶
修改AProxy为泛型类
public class AProxy<T> : RealProxy { private readonly T _decorated; public AProxy(T decorated) : base(typeof(Box)) { _decorated = decorated; } private void Log(string msg, object arg = null) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(msg, arg); Console.ResetColor(); } public override IMessage Invoke(IMessage msg) { var methodCall = msg as IMethodCallMessage; var methodInfo = methodCall.MethodBase as MethodInfo; Log("Proxy - Before executing '{0}'", methodCall.MethodName); try { var result = methodInfo.Invoke(_decorated, methodCall.InArgs); Log("Proxy - After executing '{0}' ", methodCall.MethodName); return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall); } catch (Exception e) { Log(string.Format( "Proxy- Exception {0} executing '{1}'", e), methodCall.MethodName); return new ReturnMessage(e, methodCall); } } }
客户端使用方法修改
static void Main(string[] args) { Box bigBox = new BigBox() as Box; AProxy<Box> proxyCustomer = new AProxy<Box>(bigBox); Box myEntity = proxyCustomer.GetTransparentProxy() as Box; myEntity.Open(); myEntity.Close(); }
如此一来AProxy就可以代理所有类型,达到目的
曾经年少多少事 而今皆付谈笑中!