zoukankan      html  css  js  c++  java
  • Unity Behaviors for Interception

    Unity提供了自带的拦截器,如果你并不想编写繁琐的拦截器可以选择编写更轻量的方式Behavior。拦截器的应用场景有不少,比如一些数据访问框架,它们的核心概念是AOP。通过创建一个继承于类型的代理类型,并重写它的virtual函数将拦截器置入其中。前置处理函数负责打开数据库连接、启动事务,后置处理器负责提交事务、关闭数据库连接。Unity的VirtualMethodInterceptor就可以帮助我们完成这个功能。

    如果你熟悉WPF/Silverlight,那么一定了解这两年流行的MVVM。WPF/Silverlight的数据绑定基于DataContext类型是一个DependencyObject还是一个实现了INotifyPropertyChanged接口的类型。当绑定类型的属性发生改变,数据绑定机制会主动将变化更新到UI。由于所有ViewModel都需要实现INotifyPropertyChanged接口,并且需要在每个属性的setter上显示的产生属性变化的通知:

     1 public class MainViewModel : INotifyPropertyChanged
     2 {
     3   private String m_name;
     4 
     5   public MainViewModel() { }
     6 
     7   public virtual String Name
     8   {
     9     get { return m_name; }
    10     set
    11     {
    12       if (!String.Equals(m_name, value))
    13       {
    14         m_name = value;
    15 
    16         OnPropertyChanged(“Name”);
    17       }
    18     }
    19   }
    20 
    21   private void OnPropertyChanged(String propertyName)
    22   {
    23     PropertyChangedEventHandler handler = PropertyChanged;
    24 
    25     if (handler != null)
    26       handler(this, new PropertyChangedEventArgs(propertyName));
    27   }
    28 
    29   #region INotifyPropertyChanged Members
    30 
    31   public event PropertyChangedEventHandler PropertyChanged;
    32 
    33   #endregion
    34 }

    上面的视图模型可以优化,创建一个ViewModelBase的基类,实现了INotifyPropertyChanged接口,并提供了OnPropertyChanged函数。但对于ViewModel的开发人员来说仍旧需要在各处添加触发PropertyChanged事件的函数或代码。我们可以通过Unity的VirtualMethodInterceptor,编写一个NotifyPropertyChangedBehavior实现属性变化的通知。看一个示例:

      1 // <summary>
      2 /// 属性变化行为
      3 /// </summary>
      4 public sealed class NotifyPropertyChangedBehavior : IInterceptionBehavior
      5 {
      6   /// <summary>
      7   /// 添加事件函数信息
      8   /// </summary>
      9   private static readonly MethodInfo AddEventMethodInfo = typeof(INotifyPropertyChanged).GetEvent(“PropertyChanged”).GetAddMethod();
     11 
     12   /// <summary>
     13   /// 删除事件函数信息
     14   /// </summary>
     15   private static readonly MethodInfo RemoveEventMethodInfo = typeof(INotifyPropertyChanged).GetEvent(“PropertyChanged”).GetRemoveMethod();
     17 
     18   /// <summary>
     19   /// 属性变化事件
     20   /// </summary>
     21   private event PropertyChangedEventHandler PropertyChanged;
     22 
     23   /// <summary>
     24   /// 构造函数
     25   /// </summary>
     26   public NotifyPropertyChangedBehavior() { }
     27 
     28   /// <summary>
     29   /// 是否为属性Setter
     30   /// </summary>
     31   /// <param name=”input”>输入</param>
     32   /// <returns>为属性Setter</returns>
     33   private static Boolean IsPropertySetter(IMethodInvocation input)
     34   {
     35     return input.MethodBase.IsSpecialName && input.MethodBase.Name.StartsWith(“set_”);
     36   }
     37 
     38   /// <summary>
     39   /// 添加事件订阅
     40   /// </summary>
     41   /// <param name=”input”>输入</param>
     42   /// <param name=”getNext”>下一个行为</param>
     43   /// <returns>函数返回值</returns>
     44   private IMethodReturn AddEventSubscription(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
     45   {
     46     var subscriber = (PropertyChangedEventHandler)input.Arguments[0];
     47 
     48     this.PropertyChanged += subscriber;
     49 
     50     return input.CreateMethodReturn(null);
     51   }
     52 
     53   /// <summary>
     54   /// 删除事件订阅
     55   /// </summary>
     56   /// <param name=”input”>输入</param>
     57   /// <param name=”getNext”>下一个行为</param>
     58   /// <returns>函数返回值</returns>
     59   private IMethodReturn RemoveEventSubscription(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
     60   {
     61     var subscriber = (PropertyChangedEventHandler)input.Arguments[0];
     62 
     63     this.PropertyChanged -= subscriber;
     64 
     65     return input.CreateMethodReturn(null);
     66   }
     67 
     68   /// <summary>
     69   /// 拦截属性设置
     70   /// </summary>
     71   /// <param name=”input”>输入</param>
     72   /// <param name=”getNext”>下一个行为</param>
     73   /// <returns>函数返回值</returns>
     74   private IMethodReturn InterceptPropertySet(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
     75   {
     76     var propertyName = input.MethodBase.Name.Substring(4);
     77     var returnValue = getNext()(input, getNext);
     78     var subscribers = PropertyChanged;
     79 
     80     if (subscribers != null)
     81       subscribers(input.Target, new PropertyChangedEventArgs(propertyName));
     82 
     83     return returnValue;
     84   }
     85 
     86   #region IInterceptionBehavior Members
     87 
     88   /// <summary>
     89   /// 是否将执行
     90   /// </summary>
     91   public Boolean WillExecute
     92   {
     93     get { return true; }
     94   }
     95 
     96   /// <summary>
     97   /// 获得需要的接口遍历器
     98   /// </summary>
     99   /// <returns>接口遍历器</returns>
    100   public IEnumerable<Type> GetRequiredInterfaces()
    101   {
    102     return new[] { typeof(INotifyPropertyChanged) };
    103   }
    104 
    105   /// <summary>
    106   /// 调用
    107   /// </summary>
    108   /// <param name=”input”>输入</param>
    109   /// <param name=”getNext”>下一个行为</param>
    110   /// <returns>函数返回值</returns>
    111   public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
    112   {
    113     // 如果为添加事件
    114     if (input.MethodBase == AddEventMethodInfo)
    115       return AddEventSubscription(input, getNext);
    116 
    117     // 如果为删除事件
    118     if (input.MethodBase == RemoveEventMethodInfo)
    119       return RemoveEventSubscription(input, getNext);
    120 
    121     // 设置属性
    122     if (IsPropertySetter(input))
    123       return InterceptPropertySet(input, getNext);
    124 
    125     return getNext()(input, getNext);
    126   }
    127 
    128   #endregion
    129 }
    130 
    131 public class MainViewModel
    132 {
    133   public MainViewModel() { }
    134 
    135   public virtual String Name { get; set; }
    136 }
    137 
    138 IUnityContainer unityContainer = new UnityContainer();
    139 
    140 unityContainer.AddNewExtension<Interception>();
    141 unityContainer.RegisterType<MainViewModel>(new Interceptor<VirtualMethodInterceptor>(), new InterceptionBehavior(new NotifyPropertyChangedBehavior()));
    142 
    143 MainViewModel viewModel = unityContainer.Resolve<MainViewModel>();
    144 
    145 ((INotifyPropertyChanged)viewModel).PropertyChanged += new PropertyChangedEventHandler((sender, e) => Console.WriteLine(e.PropertyName));
    146 
    147 viewModel.Name = “hello, world”;

    上面的示例可以看到MainViewModel被附加了PropertyChanged行为,开发人员不再需要为视图模型的属性变化编写大量重复的代码。一个拦截行为需要实现IInterceptionBehavior的三个定义:WillExecute属性、GetRequiredInterfaces函数、Invoke函数。

    WillExecute:定义当前行为是否将被执行,开发人员可以根据不同情况编写相应逻辑。

    GetRequiredInterfaces:返回需要被附加的接口,比如MainViewModel并没有实现INotifyPropertyChanged,但是被拦截后创建的代理类型被附加了INotifyPropertyChanged接口。

    Invoke:拦截后的真正调用,getNext是下一个行为,整个行为附加是一个链式调用。

  • 相关阅读:
    WinForm被遮挡的控件解决方案
    IC卡资料
    水晶报表2008部署
    打造最强的VC6
    SqlServer Case
    using namespace std
    非接触式IC智能(射频)卡
    删除VS2005插件

    SQLServer2005数据库自动备份
  • 原文地址:https://www.cnblogs.com/junchu25/p/2631577.html
Copyright © 2011-2022 走看看