• 如何利用Interception简化MVVM中的Model和ViewModel的设计


    这一篇是“如何利用AOP简化MVVM中Model和ViewModel的设计”一文的姊妹篇。阅读本文之前,请一定要先阅读上一篇,否则你可能对有关问题理解不深。

    上一篇说到,我们可以用AOP的方式,具体来说,我们使用了一个第三方的框架(PostSharp)来实现了代码注入。PostSharp的方式是静态注入,它是需要改变IL代码的。

    请看下面这个截图,Customer类型里面的IL代码其实是被改过的。PostSharp会改变Visual Studio的编译行为。

    image

    除了用这种方式之外,是否有其他方法呢?其实是有,我这一篇就给大家介绍另外一种做法:使用微软官方提供的Enterprise Library中的Interception功能(由Unity提供的拦截功能)

    关于Enterprise Library的介绍和下载,请访问下面的地址

    http://entlib.codeplex.com/

    本文演示的例子,是基于Enterprise Library 5.0

    我们来看下面的例子。假如我们还有一个Model类型,叫Order,表示订单。我们希望它的代码能像下面这样简练。

    using System;
    
    namespace WPFMVVMSample.Models
    {
        public class Order:ModelBase
        {
            public int OrderID { get; set; }
            public DateTime OrderDate { get; set; }
        }
    }
    

    【注意】我们这里只继承了ModelBase,没有其他任何特别的东西。

    请放心,我们可以做到。你只要继续往下读就可以了。

    1. 添加引用

    我们需要引用一个程序集

    image

    2. 编写一个InterceptionBehavior

    Behavior是指我们需要注入的一种行为。这是Interception中的专业术语。

    【注意】这一篇文章不是专门来讲Policy Injection的,有兴趣的朋友,可以参考Enterprise Library中的说明文档

    using System.Linq;
    using Microsoft.Practices.Unity.InterceptionExtension;
    
    namespace WPFMVVMSample
    {
        public class NotifyPropertyChangedBahavior:IInterceptionBehavior
        {
    
    
            public System.Collections.Generic.IEnumerable<System.Type> GetRequiredInterfaces()
            {
                return Enumerable.Empty<System.Type>();
    
            }
    
            public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
            {
    
    
                var result= getNext()(input, getNext);//先执行方法
    
    
                var methodName = input.MethodBase.Name;
                var type = input.Target.GetType();
                var targetMethod = type.GetMethod("OnPropertyChanged",
                    System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
    
                if (methodName.StartsWith("set_") && targetMethod != null)//只针对这种方法器进行注入
                {
                    var propertyName = methodName.Substring(4);//解析得到属性名称
                    targetMethod.Invoke(input.Target, new[] { propertyName });//执行该方法
                }
    
                return result;
            }
    
            public bool WillExecute
            {
                get { return true; }
            }
        }
    }
    

    【注意】上述代码与之前用PostSharp的做法是很相似的,不是吗

    3. 修改ModelBase类型

    Unity默认提供的Intercept,支持两种主要的拦截器:TransparentProxyInterceptor和VirtualMethodInterceptor。我们这里准备用第一种。它有一个简单要求,就是需要拦截的类型,继承MarshalByRefObject即可

    代码修改如下

    using System;
    using System.ComponentModel;
    using System.Diagnostics;
    
    namespace WPFMVVMSample.Models
    {
        public abstract class ModelBase : MarshalByRefObject, INotifyPropertyChanged
        {
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected void OnPropertyChanged(string name)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(name));
    
                //为了便于调试,我们在Output窗口输出一行信息
                Debug.WriteLine(string.Format("{0} Changed", name));
            }
    
        }
    }
    

    4.编写代码实现拦截和注入

    using System;
    using System.Windows;
    
    using Microsoft.Practices.Unity.InterceptionExtension;
    
    
    namespace WPFMVVMSample
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
                Loaded += new RoutedEventHandler(MainWindow_Loaded);
            }
    
    
    
    
    
            void MainWindow_Loaded(object sender, RoutedEventArgs e)
            {
    
                var order = Intercept.ThroughProxy(new Models.Order(),
                    new TransparentProxyInterceptor(),
                    new[] { new NotifyPropertyChangedBahavior() });
    
                order.OrderDate = DateTime.Now;
                order.OrderID = 5;
    
                
            }
        }
    }
    
    请注意,这里不能再直接用new的方式创建Order的实例,而是需要通过Intercept来创建。
     
    按下F5进行调试,我们同样可以在Output窗口看到有关的消息输出,这说明那个自定义Behavior在起作用,因为是它在调用基类中那个OnPropertyChanged方法
     
    image
     
    值得一提的是,与PostSharp不同,我们这里使用的Interception,是动态拦截,它不会修改我们的代码。请看Order这个类型的代码,与我们在Visual Studio里面是一样的
    image
     
     
  • 相关阅读:
    多说社交评论插件学习《一》
    《转》每天起床时,优秀创业者都会问自己这3个问题
    老赵面试题参考答案(二)《转》
    老赵面试题参考答案(一)《转》
    20个开源项目托管站点推荐
    .NET面试题(二)
    .NET面试题(一)
    Python笔记(28)-----继承
    pytorch实战(2)-----回归例子
    深度学习之入门Pytorch(1)------基础
  • 原文地址:https://www.cnblogs.com/chenxizhang/p/2089431.html
Copyright © 2020-2023  润新知