williambirkin

恭喜发财!

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

本文实例选自《设计模式--基于c#的工程化实现及扩展》

原文的目的是通过.NET对AOP机制的原生支持实现Decorator模式。

 

基础原理(摘自Artech 的 Enterprise Library Policy Injection Application Block 之二: PIAB设计和实现原理):

MBRObjRefRealProxyTransparentProxy,对于这些名词,我想熟悉或者接触过.NET Remoting的人肯定不会不陌生。由于PIAB的实现机制依赖于Remoting的这种Marshaling,如果对此不了解的读者将对后面的介绍很难理解,所以很有必要先做以下简单的介绍。

我们知道,CLR通过AppDomain实现不同Application之间的隔离,在通常情况下,不同AppDomain不同共享内存。在一个AppDomain中创建的对象不能直接被运行在另一个AppDomain的程序使用。跨AppDomain对象的共享依赖于一个重要的过程:Marshaling。我们有两种不同的Marshaling方式:Marshaling by ValueMarshaling by Reference。前者采用的是Serialization/Deserialization的方式,而后者则是采用传递Reference的方式来实现,其实现原来如下:

Remoting Infrastructure先生成对象的ObjRef InstanceObjRefSystem.Runtime.Remoting.ObjRef)代表远程对象的一个Reference,存储着跨AppDomain远程调用所需的所有的信息,比如URI、类型的层次结构、以及实现的Interface等等。ObjRef是可以序列化的,也就是说它可以按照by Value的方式进行Marshaling。所以可以这么说Marshaling by Reference依赖对对ObjRefMarshaling by Value

ObjRef产地到另一个AppDomain的实现,将根据ObjRef的数据生成两个Proxy对象:RealProxyTransparentProxyRealProxy根据ObjRef创建,通过RealProxy创建TransparentProxy。当进行远程调用的时候,Client直接和TransparentProxy打交道,对TransparentProxy的调用将会ForwardRealProxyRealProxy通过Remoting InfrastructureCommunicateActivation机制将Invocate传递给被激活的Remote Object

MBR通常在一个跨AppDomain的环境下实现远程调用,但是这种机制在用一个AppDomian依然有效,而且可以免去跨AppDomain的性能损失。PIAB就是充分运用了这种在同一个AppDomain下的MBR

 

下面这个简单AOP 的例子也是使用了以上思想。通过在RealProxy中增加对目标方法调用的拦截。然后将调用的处理权交由目标方法上的标签类进行处理。在标签类处理完各种检验后RealProxy再执行对目标方法的调用。

 

代码如下:

 

 

定义装饰标签的基类
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
public abstract class DecoratorAttributeBase : Attribute
{
public abstract void Intercept(object target);
}

 

 

 

定义代理类
 
      /// <summary>
  
/// 实际代理对象
   /// </summary>
public class CustomProxy<T> : RealProxy, IDisposable where T : MarshalByRefObject
{
/// <summary>
/// 构造过程中把Proxy需要操作的内容与实际目标对象实例Attach到一起
/// </summary>
/// <param name="target"></param>
public CustomProxy(T target):base(target.GetType())
{
AttachServer(target);
}

#region IDisposable 成员
/// <summary>
/// 析构过程则借助Proxy和目标对象实例的Attach,便于GC回收
/// </summary>
public void Dispose()
{
DetachServer();
}

#endregion

/// <summary>
/// 创建目标实例的transparent代理对象
/// </summary>
/// <param name="target"></param>
/// <returns></returns>
public static T Create(T target)
{
if (target == null)
{
throw new ArgumentNullException("target");
}

return (T)(new CustomProxy<T>(target).GetTransparentProxy());
}

public override IMessage Invoke(IMessage msg)
{
MethodCallMessageWrapper caller
= new MethodCallMessageWrapper((IMethodCallMessage)msg);

//提取实际宿主对象
MethodInfo method = (MethodInfo)caller.MethodBase;

T target
= (T)GetUnwrappedServer();

DecoratorAttributeBase[] attributes
=
(DecoratorAttributeBase[])method.GetCustomAttributes(
typeof(DecoratorAttributeBase), true);

if (attributes.Length > 0)
{
foreach (DecoratorAttributeBase attribute in attributes)
{
attribute.Intercept(caller);
}
}

object ret = method.Invoke(target,caller.Args);

return new ReturnMessage(ret, caller.Args, caller.ArgCount, caller.LogicalCallContext, caller);

}
}

 

 

定义具体装饰属性
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class ArgumentNotEmptyAttribute : DecoratorAttributeBase
{
public override void Intercept(object target)
{
MethodCallMessageWrapper caller
= new MethodCallMessageWrapper((IMethodCallMessage)target);

if (caller.ArgCount == 0)
{
return;
}

foreach (object arg in caller.Args)
{
if ((string.IsNullOrEmpty((string)arg)))
{
throw new ArgumentException("string is null or empty");
}
}
}
}

[AttributeUsage(AttributeTargets.Method, AllowMultiple
= false)]
public class ArgumentTypeRestrictionAttribute : DecoratorAttributeBase
{
private Type type;
public ArgumentTypeRestrictionAttribute(Type type)
{
this.type = type;
}

public override void Intercept(object target)
{
MethodCallMessageWrapper caller
= new MethodCallMessageWrapper((IMethodCallMessage)target);

if (caller.ArgCount == 0)
{
return;
}

for (int i = 0; i < caller.ArgCount; i++)
{
object arg = caller.Args[i];

if ((arg.GetType() != this.type) && (!arg.GetType().IsAssignableFrom(this.type)))
{
throw new ArgumentException(i.ToString());
}
}
}
}

 

 

客户类型
class User : MarshalByRefObject
{
private string name;
private string title;

[ArgumentTypeRestriction(
typeof(string))] // 提供拦截入口
[ArgumentNotEmpty()] // 提供拦截入口
public void SetUserInfo(object name, object title)
{
this.name = (string)name;
this.title = (string)title;
}
}

 

测试代码
[TestMethod]
public void TestCSharpAOP()
{
User user
= CustomProxy<User>.Create(new User());

user.SetUserInfo(
"joe","manager");

try
{
user.SetUserInfo(
20, "manager");
}
catch (Exception ex)
{
Assert.AreEqual
<string>("0", ex.Message);
}

try
{
user.SetUserInfo(
"", "manager");
}
catch (Exception ex)
{
Assert.AreEqual
<string>("string is null or empty", ex.Message);
}
}

 

 

 

 

收录这段代码只是为了了解下.NET下实现AOP机制的基本方式。如果想在项目中使用AOP机制,我觉得还是使用Enterprise Lirbrary 的PIAB吧。

自己实现AOP的框架需没有太大必要了。

 

另外书中还列举了一种使用MSIL的实现方式。感觉比较复杂没有太深入。

 

本文有点炒剩饭。。。纯属个人备忘

posted on 2010-03-23 23:18  williambirkin  阅读(514)  评论(0编辑  收藏  举报