【问题标题】:How to configure Unity 2.0 at runtime to intercept INotifyPropertyChanged?如何在运行时配置 Unity 2.0 以拦截 INotifyPropertyChanged?
【发布时间】:2014-07-08 04:47:00
【问题描述】:

http://msdn.microsoft.com/en-us/library/ff660851(v=PandP.20).aspx 提供了如何实现 IInterceptionBehavior 以添加 INotifyPropertyChanged 支持的示例。该示例不包括如何配置 NotifyPropertyChangedBehavior 以在运行时使用。我所做的所有谷歌搜索都没有给我一个有效的答案。

我是 AOP 和 IoC 的新手,所以也许我的概念也有误。这就是我想做的:

using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;

static class AppMain
{
    public static void Main()
    {
        // Configure Unity.
        var container = new UnityContainer();

        container.AddNewExtension<Interception>();

        // todo: Register an interface instead of a type.
        container.RegisterType<Customer>(new Interceptor<VirtualMethodInterceptor>(), 
                                         new InterceptionBehavior<NotifyPropertyChangedBehavior>());

        var propertyChangedCount = 0;
        var customer = new Customer();

        customer.PropertyChanged += (s, e) => propertyChangedCount += 1;

        // Update customer and send property changed event.
        customer.FirstName = "what ever";

        if (propertyChangedCount != 1)
        {
            Console.Write("Failed!");
        }
        else
        {
            Console.WriteLine("Success!");
        }

        Console.WriteLine();
        Console.WriteLine("Press any key to continue...");
        Console.ReadKey();

    }

    static void customer_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        throw new NotImplementedException();
    }

    public class Customer : MarshalByRefObject, INotifyPropertyChanged
    {

        private string _firstName;
        public event PropertyChangedEventHandler PropertyChanged;

        // todo: Does the property have to be virtual (overridable).
        public virtual string FirstName
        {
            get { return _firstName; }
            set
            {
                _firstName = value;
                // Unity Interception to do the following RaiseEvent
                //if (PropertyChanged != null)
                //{
                //    PropertyChanged(this, new PropertyChangedEventArgs("FirstName"));
                //}
            }
        }

    }

    // Copied from http://msdn.microsoft.com/en-us/library/ff660851(v=PandP.20).aspx
    class NotifyPropertyChangedBehavior : IInterceptionBehavior
    {
        private event PropertyChangedEventHandler propertyChanged;

        private static readonly MethodInfo addEventMethodInfo =
            typeof(INotifyPropertyChanged).GetEvent("PropertyChanged").GetAddMethod();

        private static readonly MethodInfo removeEventMethodInfo =
            typeof(INotifyPropertyChanged).GetEvent("PropertyChanged").GetRemoveMethod();

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            if (input.MethodBase == addEventMethodInfo)
            {
                return AddEventSubscription(input, getNext);
            }
            if (input.MethodBase == removeEventMethodInfo)
            {
                return RemoveEventSubscription(input, getNext);
            }
            if (IsPropertySetter(input))
            {
                return InterceptPropertySet(input, getNext);
            }
            return getNext()(input, getNext);
        }

        public bool WillExecute
        {
            get { return true; }
        }

        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return new[] { typeof(INotifyPropertyChanged) };
        }

        private IMethodReturn AddEventSubscription(IMethodInvocation input, 
                                                   GetNextInterceptionBehaviorDelegate getNext)
        {
            var subscriber = (PropertyChangedEventHandler)input.Arguments[0];

            propertyChanged += subscriber;
            return input.CreateMethodReturn(null);
        }

        private IMethodReturn RemoveEventSubscription(IMethodInvocation input, 
                                                      GetNextInterceptionBehaviorDelegate getNext)
        {
            var subscriber = (PropertyChangedEventHandler)input.Arguments[0];

            propertyChanged -= subscriber;
            return input.CreateMethodReturn(null);
        }

        private static bool IsPropertySetter(IMethodInvocation input)
        {
            return input.MethodBase.IsSpecialName && input.MethodBase.Name.StartsWith("set_");
        }

        private IMethodReturn InterceptPropertySet(IMethodInvocation input, 
                                                   GetNextInterceptionBehaviorDelegate getNext)
        {
            var propertyName = input.MethodBase.Name.Substring(4);
            var returnValue = getNext()(input, getNext);
            var subscribers = propertyChanged;

            if (subscribers != null)
            {
                subscribers(input.Target, new PropertyChangedEventArgs(propertyName));
            }

            return returnValue;
        }
    }
}

【问题讨论】:

    标签: c# unity-container aop inotifypropertychanged


    【解决方案1】:

    提姆

    一些 IL 编织不会让这更容易吗?

    NotifyPropertyWeaverhttp://www.sharpcrafters.com/ ?

    【讨论】:

    • 第一个链接失效了
    【解决方案2】:

    它是herehere。基本上,你必须注册类型和拦截器:

    Dim container As IUnityContainer = New UnityContainer()
       container.AddNewExtension(Of Interception)()
       container.RegisterType(Of Customer)( _
              New Interceptor(Of VirtualMethodInterceptor)(), _
              New InterceptionBehavior(Of NotifyPropertyChangedBehavior)())
    

    【讨论】:

    • 您的代码编译并看似运行,但客户未按预期引发 PropertyChanged 事件。我已将源代码更改为 c#。这似乎会导致更多人阅读帖子。
    • 发现错误,拦截器必须是TransparentProxyInterceptor,而不是VirtualMethodInterceptor。
    【解决方案3】:

    我需要使用 VirtualMethodInterceptor。我发现 NotifyPropertyChangedBehavior.Invoke 检查 PropertyChanged 添加或删除从来都不是真的。我更改为检查方法名称匹配并且一切正常。

    最初的 NotifyPropertyChangedBehavior 来自 msdn 上的 Unity 文档。如果有人能告诉我为什么原始代码不起作用,我很感兴趣。

    类定义

    public class NotifyPropertyChangeClass 
        : INotifyPropertyChanged
    {
        public virtual int SomeInt { get; set; }
    
        public virtual event PropertyChangedEventHandler PropertyChanged;
    }
    

    统一容器设置

    container.AddNewExtension<Interception>();
    container.RegisterType<NotifyPropertyChangeClass>(
        new Interceptor<VirtualMethodInterceptor>(),
        new InterceptionBehavior(new NotifyPropertyChangedBehavior()));
    

    NotifyPropertyChangedBehavior 修改 (original)

    public class NotifyPropertyChangedBehavior : IInterceptionBehavior
    {
    ...
        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            if (input.MethodBase.Name.Equals(addEventMethodInfo.Name))//(input.MethodBase == addEventMethodInfo)
            {
                return AddEventSubscription(input, getNext);
            }
            if (input.MethodBase.Name.Equals(removeEventMethodInfo.Name))//(input.MethodBase == removeEventMethodInfo)
            {
                return RemoveEventSubscription(input, getNext);
            }
            if (IsPropertySetter(input))
            {
                return InterceptPropertySet(input, getNext);
            }
            return getNext()(input, getNext);
        }
    ...
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-10
      • 2011-09-02
      • 2011-07-29
      • 2013-06-17
      • 2013-05-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多