博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Unity Behaviors for Interception
阅读量:6847 次
发布时间:2019-06-26

本文共 5733 字,大约阅读时间需要 19 分钟。

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     set11     {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 Members30 31   public event PropertyChangedEventHandler PropertyChanged;32 33   #endregion34 }

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

1 //   2 /// 属性变化行为  3 ///   4 public sealed class NotifyPropertyChangedBehavior : IInterceptionBehavior  5 {  6   ///   7   /// 添加事件函数信息  8   ///   9   private static readonly MethodInfo AddEventMethodInfo = typeof(INotifyPropertyChanged).GetEvent(“PropertyChanged”).GetAddMethod(); 11  12   ///  13   /// 删除事件函数信息 14   ///  15   private static readonly MethodInfo RemoveEventMethodInfo = typeof(INotifyPropertyChanged).GetEvent(“PropertyChanged”).GetRemoveMethod(); 17  18   ///  19   /// 属性变化事件 20   ///  21   private event PropertyChangedEventHandler PropertyChanged; 22  23   ///  24   /// 构造函数 25   ///  26   public NotifyPropertyChangedBehavior() { } 27  28   ///  29   /// 是否为属性Setter 30   ///  31   /// 输入 32   /// 
为属性Setter
33   private static Boolean IsPropertySetter(IMethodInvocation input) 34   { 35     return input.MethodBase.IsSpecialName && input.MethodBase.Name.StartsWith(“set_”); 36   } 37 38   /// 39   /// 添加事件订阅 40   /// 41   /// 输入 42   /// 下一个行为 43   ///
函数返回值
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   /// 54   /// 删除事件订阅 55   /// 56   /// 输入 57   /// 下一个行为 58   ///
函数返回值
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   /// 69   /// 拦截属性设置 70   /// 71   /// 输入 72   /// 下一个行为 73   ///
函数返回值
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   /// 89   /// 是否将执行 90   /// 91   public Boolean WillExecute 92   { 93     get { return true; } 94   } 95 96   /// 97   /// 获得需要的接口遍历器 98   /// 99   ///
接口遍历器
100   public IEnumerable
GetRequiredInterfaces()101   {102     return new[] { typeof(INotifyPropertyChanged) };103   }104 105   ///
106   /// 调用107   /// 108   ///
输入109   ///
下一个行为110   ///
函数返回值
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   #endregion129 }130 131 public class MainViewModel132 {133   public MainViewModel() { }134 135   public virtual String Name { get; set; }136 }137 138 IUnityContainer unityContainer = new UnityContainer();139 140 unityContainer.AddNewExtension
();141 unityContainer.RegisterType
(new Interceptor
(), new InterceptionBehavior(new NotifyPropertyChangedBehavior()));142 143 MainViewModel viewModel = unityContainer.Resolve
();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是下一个行为,整个行为附加是一个链式调用。

转载地址:http://hzoul.baihongyu.com/

你可能感兴趣的文章
ODBC 、DAO 、ADO 、OLEDB 数据库连接方式区别及联系
查看>>
First glance in Go
查看>>
24点经典算法
查看>>
.net(C#)访问Oracle数据库的几种免安装组件的对比(转)
查看>>
Java反射机制<2>
查看>>
Centos7网络配置+图形界面设置
查看>>
小酌重构系列[9]——分解依赖
查看>>
如果你想深刻理解ASP.NET Core请求处理管道,可以试着写一个自定义的Server
查看>>
MySQL · 引擎特性 · InnoDB 事务锁简介
查看>>
USB的四种传输类型
查看>>
contextmenu="supermenu" 属性的应用 右键菜单打开和保存功能
查看>>
PL-SQL 包的创建和应用
查看>>
RecyclerView onItemClick button和布局都有单击事件时的处理方式
查看>>
JAVA入门[20]-Spring Data JPA简单示例
查看>>
复旦大学高等代数在线课程的学习要求
查看>>
Hadoop生态圈-kafka事务控制以及性能测试
查看>>
哪里有免费硬盘恢复数据软件下载
查看>>
面试:谁说的无序就不能用二分查找?
查看>>
ES6 Map数据结构
查看>>
MAP 最大后验——利用经验数据获得对未观测量的点态估计
查看>>