详细讲解相关ContextOperationBaseAttribute知识

对_JoinOperation方法的解释我们留在后面,这里是一个数据结构。将ContextOperationBaseAttribute
   
    类型串成链表,让方法的执行穿过所有的ContextOperationBaseAttribute处理类。
   
    2.3上下文对象的后期绑定实现
   
    为了让绑定对象支持上下文后期绑定,需要一个特性作为表示。
   
    [csharp]
   
    /***
   
    * author:深度训练
   
    * blog:http://wangqingpei557.blog.51cto.com/
   
    * **/
   
    using System;
   
    using System.Collections.Generic;
   
    using System.Text;
   
    namespace ContextModule
   
    {
   
    /// <summary>
   
    /// 确定设置类是否需要后期动态绑定到上下文。
   
    /// 使用该特性的类将是上下文活跃的,只有在使用的时候才确定当前上下文。
   
    /// </summary>
   
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
   
    public class ContextEveningBoundAttribute : Attribute
   
    {
   
    public ContextEveningBoundAttribute() { }
   
    private bool _isEvening;
   
    /// <summary>
   
    /// 指定对象是否需要后期动态绑定上下文。
   
    /// </summary>
   
    public bool IsEvening { set { _isEvening = value; } get { return _isEvening; } }
   
    }
   
    }
   
    仅仅为了标识后期绑定说明。在ContextModuleBaseObject 对象的构造函数中可以看到。
   
    [csharp]
   
    public ContextModuleBaseObject()
   
    {
   
    if (typeof(T)。GetCustomAttributes(typeof(ContextEveningBoundAttribute), false) != null)
   
    {
   
    _IsEvening = true;
   
    return;
   
    }
   
    //前期静态绑定上下文
   
    if (ContextRuntime.CurrentContextRuntime == null)
   
    throw new Exception(“上下文环境未能初始化,请检查您的代码入口是否启用了ContextRuntime对象。”);
   
    _contextRunTime = ContextRuntime.CurrentContextRuntime;
   
    _InitContextHandler<T>();
   
    }
   
    到这里我们已经实现对象的动态绑定到上下文来,下面我们来分析Context如何用AOP配合完成面向切面编程的机制。
   
    2.4.AOP中的对象行为的契约设计实现
   
    其实这里的契约设计也就是图2中对AOP中的“面”的约定。
   
    AOP全称为“面向切面编程”.对象在运行时具备多个面,其实在。NET里面我们习惯性的用特性(Attribute)来表达这个概念。因为不需要改动任何代码就可以将特性加到对象中的任何元素中去,在不同的业务环节或者说是功能环节就能动态的转动元素体现出“切面”的优势,健康知识平台重庆治疗附睾炎哪家最好当然具体的实现可能很多种,这里使用特性来完成。
在此约定任何处理对象方法的“面”都将被抽象。这里我将命名为ContextOperationBaseAttribute该特性表示所有附加到方法上的特性的基类,对“面”的抽象。
   
    那么不同类型的面将有着不同的操作行为,比如:记录日志的特性、计算性能的特性、认证安全的特性他们都有着不同的行为和属性,所以这里我们还需要提取一个顶层接口作为行为类的特性处理抽象。这里我将命名为IContextOperationHandler该接口作为统一执行行为特性的高层依赖。其实这里也体现出依赖倒置原则,依赖抽象不依赖具体实现。
   
    完整的ContextOperationBaseAttribute 类:
   
    [csharp]
   
    /***
   
    * author:深度训练
   
    * blog:http://wangqingpei557.blog.51cto.com/
   
    * **/
   
    using System;
   
    using System.Collections.Generic;
   
    using System.Text;
   
    namespace ContextModule
   
    {
   
    /// <summary>
   
    /// 上下文操作动作特性化基类。
   
    /// 所有对上下文中的类、方法的过滤操作都必须继承此类。
   
    /// </summary>
   
    public abstract class ContextOperationBaseAttribute : Attribute, IContextOperationHandler
   
    {
   
    /// <summary>
   
    /// 过滤器的处理顺序,从小到大的方式进行处理。
   
    /// </summary>
   
    public int OperationSort { get; set; }
   
    /// <summary>
   
    /// 下一次过滤操作类
   
    /// </summary>
   
    internal ContextOperationBaseAttribute NextOperation { get; set; }
   
    /// <summary>
   
    /// 开始处理过滤对象
   
    /// </summary>
   
    /// <typeparam name=“Result”>方法的返回值类型</typeparam>
   
    /// <param name=“actionmethod”>调用的方法包装</param>
   
    /// <param name=“paramarray”>方法的有序参数</param>
   
    /// <returns></returns>
   
    public virtual Result ResultAction<Result>(ContextMethodInfo actionmethod, params object[] paramarray)
   
    {
   
    object result = null;
   
    if (!actionmethod.IsPost)
   
    {
   
    result = (this as IContextOperationHandler)。Operation(actionmethod, paramarray);
   
    if (this.NextOperation != null)
   
    return this.NextOperation.ResultAction<Result>(actionmethod, paramarray);
   
    }
   
    if (result != null)
   
    return (Result)result;
   
    return default(Result);
   
    }
   
    public abstract object Operation(ContextMethodInfo contextmethod, params object[] paramarray);
   
    }
   
    }
   
    作为抽象的顶层类需要完成派生类重复的劳动。这里实现了一个ResultAction泛型方法,该方法是外部调用绑定对象的方法时的入口点。但是具体的实现区别在于IContextOperationHandler 接口的定义。
   
    由于行为的特性可能存在多个,所以对于最后一个处理完的特性需要结束整个的调用链表,并且返回值。在ResultAction虚方法里面对IContextOperationHandler 接口的Operation方法执行调用,该方法将会在实现特定行为特性里面实现,这里又体现出“模板方法”设计模式。在抽象类中约定行为,在派生类中实现具体。
   
    这里比较有意思的是,特性不在像大家实现ORM的那中简单的标识了。其实特性真正强大的地方在于运行时能动态的获取到,这得益于。NET元数据的功劳。并且动态实例化然后当作普通的对象实例使用。这个观念很多。NET程序员不宜转变。
   
    在这里的ContextOperationBaseAttribute 又描述了另外一种数据结构“单向链表”,为了将绑定对象的行为最大化的在特性中实现,我们将方法的调用完全的传递到实现特性中去。那么对方法上多个作用的特性如何穿过呢,并且能保证数据的正常传递和返回。有两点我们需要注意,一个是特性的作用顺序,二个是特性对方法的执行是否完成。这两点我们都要考虑进去,所以在ContextOperationBaseAttribute 类中用public int OperationSort { get; set; }属性表示特性的执行顺序,记录日志的特性和计算性能的特性我们很难在这里定死,需要根据后期程序的执行情况而定,如我要先记录日志然后在执行方法。
   
    那么我们又如何将ContextOperationBaseAttribute类型串联起来呢?在ContextModuleBaseObject
   
    泛型绑定类中我们在构造的时候就将通过ContextOperationBaseAttribute. OperationSort 属性初始化了特性处理链表。
   
    那么我们如何将具体的对象与特性关联建立起对应关系呢?一个行为可能有多个ContextOperationBaseAttribute的实现。所以这里我们需要一个能满足行为与特性之间的数据结构。
   
    这里我将它定义为ContextFilterHandlerMap该类继承自Dictionary<string,ContextOperationBaseAttribute>泛型字典类,使用KEY-VALUE的方式存放行为与ContextOperationBaseAttribute处理特性的对应关系。
   
    [csharp]
   
    /***
   
    * author:深度训练
   
    * blog:http://wangqingpei557.blog.51cto.com/
   
    * **/
   
    using System;
   
    using System.Collections.Generic;
   
    using System.Text;
   
    namespace ContextModule
   
    {
   
    /// <summary>
   
    /// 特定于上下文的过滤器映射表。
   
    /// 上下文中的任何方法如果需要进行上下文管理的,则使用ContextModule.ContextOperationBaseAttribute特性派生类进行管理。
  /// 所有附加于方法、类上的特性管理类都将被映射到ContextModule.ContextFilterHandlerMap实例中。
   
    /// </summary>
   
    public class ContextFilterHandlerMap : Dictionary<string, ContextOperationBaseAttribute>
   
    {
   
    public ContextFilterHandlerMap() { }
   
    /// <summary>
   
    /// 获取方法对应的过滤器处理特性
   
    /// </summary>
   
    /// <param name=“mapname”>映射Key</param>
   
    /// <returns>ContextOperationBaseAttribute特性实例</returns>
   
    public ContextOperationBaseAttribute MapOperation(string mapname)
   
    {
   
    return this[mapname];
   
    }
   
    /// <summary>
   
    /// 设置过滤器与特定方法的映射
   
    /// </summary>
   
    /// <param name=“mapname”>映射Key</param>
   
    /// <param name=“operationlist”>过滤器特性基类ContextOperationBaseAttribute</param>
   
    public void MapOperation(string mapname, ContextOperationBaseAttribute operationlist)
   
    {
   
    this.Add(mapname, operationlist);
   
    }
   
    }
   
    }
   
    最后只需要向外提供IContextOperationHandler 接口就可以实现方法与处理特性的串联了。
   
    [csharp]
   
    /***
   
    * author:深度训练
   
    * blog:http://wangqingpei557.blog.51cto.com/
   
    * **/
   
    using System;
   
    using System.Collections.Generic;
   
    using System.Text;
   
    using System.IO;
   
    namespace ContextModule
   
    {
   
    /// <summary>
   
    /// 上下文操作管理接口
   
    /// </summary>
   
    public interface IContextOperationHandler
   
    {
   
    /// <summary>
   
    /// 开始上下文处理
   
    /// </summary>
   
    /// <param name=“contextmethod”>CRL目前正在执行的上下文方法的信息。
   
    /// 可以通过ContextMethodInfo实例获取方法详细信息。</param>
   
    ///<param name=“paramarray”>参数数组</param>
   
    object Operation(ContextMethodInfo contextmethod, params object[] paramarray);
   
    }
   
    }
   
    通过对外公开接口,让实现“面”的客户端去完成对具体对象方法的执行。ContextMethodInfo 类型是包装System.Reflection. MethodInfo方法元数据的,将通过调用切入到方法内部。
   
    这里基本上实现了AOP对行为的多面支持,下面我们来看一下如果动态的切入到方法中。
   
    2.5.动态入口的实现
   
    对所有方法的调用将是比较头疼的。由于一般面向上下文、面向切面都是有编写者控制对方法的调用,可以很方便的通过后台的隐式的调用。但是作为普通的方法的入口调用主要有三种方式实现。
   
    1):委托实现入口
   
    通过使用System.Delegate动态派生类型来完成对方法的调用,但是委托对于方法的签名必须是强类型的,所以很难做到通用的调用入口。
   
    2):反射实现入口(通过扩展方法在OBJECT基类中加入获取MethodInfo对象的方法,使用时通过该方法获取调用方法的信息)
   
    通过扩展方法在System.Object中加入一个扩展方法用来获取调用方法的信息,然后通过反射动态的调用,这种方法只比较常用的。但是如何框架是在。NET2.0中使用的扩展方法还不能实现,这里我是在ContextModuleBaseObject基类中加了一个类似扩展方法的方式。绑定对象可以很方便的获取到调用方法的MethodInfo对象。
3):完美的动态编译(向抽象、多态敬礼)
   
    最为完美的是扩展代码生成提供程序,在使用的对象里面在派生一个类,专门用来进行多态的转移,让高层的调用顺利进入到派生的类中。不过比较复杂。
   
    这里是使用第二种方式使用的:
   
    [csharp]
   
    /***
   
    * author:深度训练
   
    * blog:http://wangqingpei557.blog.51cto.com/
   
    * **/
   
    using System;
   
    using System.Collections.Generic;
   
    using System.Text;
   
    using System.Reflection;
   
    namespace ContextModule
   
    {
   
    /// <summary>
   
    /// 面向上下文的操作类。
   
    /// 对上下文发起的方法调用需要通过该基类进行调用才能让我们的扩展点使用成为可能。
   
    /// </summary>
   
    public static class ContextAction
   
    {
   
    /// <summary>
   
    /// 在面向上下文的环境中进行方法的调用。
   
    /// </summary>
   
    /// <typeparam name=“PostObjectType”>调用的上下文绑定对象类型</typeparam>
   
    /// <typeparam name=“ResultType”>方法的返回类型</typeparam>
   
    /// <param name=“post”>调用的上下文绑定对象的实例</param>
   
    /// <param name=“method”>方法的信息对象MethodInfo,通过Oject.GetContextMethodInfo方法自动获取。</param>
   
    /// <param name=“paramarray”>方法的有序参数集合</param>
   
    /// <returns>ResultType泛型类型指定的返回实例</returns>
   
    public static ResultType PostMethod<PostObjectType, ResultType>(PostObjectType post, MethodInfo method, params object[] paramarray)
   
    where PostObjectType : ContextModuleBaseObject<PostObjectType>
   
    {
   
    _LockPostObejctIsEveningBound<PostObjectType>(post);
   
    string key = string.Format(“{0}.{1}”, method.DeclaringType.FullName, method.Name);
   
    if (!ContextRuntime.CurrentContextRuntime.FilterMap.ContainsKey(key))
   
    {
   
    throw new Exception(string.Format(“方法{0}未经过上下文进行管理。”, key));
   
    }
   
    ContextMethodInfo contextmethod = new ContextMethodInfo(method, post);
   
    return ContextRuntime.CurrentContextRuntime.FilterMap[key].ResultAction<ResultType>(contextmethod, paramarray);
   
    }
   
    /// <summary>
   
    /// 检查调用实例类是否属于后期绑定。
   
    /// 通过使用ContextModule.ContextEveningBound(IsEvening = true)方式指定后期绑定上下文。
   
    /// </summary>
   
    private static void _LockPostObejctIsEveningBound<PostObjectType>(PostObjectType post)
   
    where PostObjectType : ContextModuleBaseObject<PostObjectType>
   
    {
   
    ContextModuleBaseObject<PostObjectType> contextclass = post as ContextModuleBaseObject<PostObjectType>;
   
    if (contextclass._IsEvening)
   
    contextclass._EveningBoundChildClass<PostObjectType>();
   
    }
   
    }
   
    }
   
    所有的调用均使用PostMethod泛型方法启动。_LockPostObejctIsEveningBound私有方法,判断当前类型是否是后期绑定,如果是则需要切入到基类中调用_ EveningBoundChildClass方法进行ContextOperationBaseAttribute 类型的链表构造,然后直接通过头对象进行调用。
   
    3.实例上下文与静态上下文
   
    对于实例上下文同时也就存在静态上下文的概念,对于静态对象的逻辑归纳有点难度,由于静态对象在面向对象设计方面很难抽象。只能通过特性注入的方式强制性的将静态对象拉入上下文。但是在多线程的情况下,确实是可以研究的。将静态对象全部进行线程本地存储,强制性的进行类似实体对象的管理。
   
    4.面向上下文的领域模型(DMM)
   
    基于上下文的使用模式可以进行领域模型的初步构造,可以先向领域中的大比例结构靠近,将业务模型逻辑归纳到一定的Context中,对业务的模块化梳理也是一种实现。[王清培版权所有,转载请给出署名]
   
    在分层架构中的业务逻辑层可能需要加入上下文的管理,将业务模型进行运行时控制。比如订单处理,将订单业务流程相关的模型对象归纳为一块。比如用户相关,将用户管理的业务流程相关的模型对象归纳为一块,确实是很有意思。
---------10

posted on 2012-08-22 15:45  时代先进程序  阅读(188)  评论(0)    收藏  举报