如何在运行时配置Unity 2.0来拦截INotifyPropertyChanged?

发布于 2024-10-04 22:47:44 字数 5257 浏览 0 评论 0原文

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;
        }
    }
}

http://msdn.microsoft.com/en-us/library/ff660851(v=PandP.20).aspx provides a sample of how to implement IInterceptionBehavior to add INotifyPropertyChanged support. What the sample does not include is how to configure NotifyPropertyChangedBehavior to be used at runtime. All the googling I've done has not given me a working answer.

I'm new to AOP and IoC so maybe I've got the concept wrong as well. This is what I want to do:

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;
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

蓝色星空 2024-10-11 22:47:44

Tim

一些 IL 编织不会让这件事变得更容易吗?

NotifyPropertyWeaverhttp://www.sharpcrafters.com/

Tim

Wouldn't some IL weaving make this easier?

NotifyPropertyWeaver Or http://www.sharpcrafters.com/ ?

空‖城人不在 2024-10-11 22:47:44

位于此处此处。基本上,您必须注册类型和拦截器:

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

It's here and here. Basically, you have to register the type and the interceptor:

Dim container As IUnityContainer = New UnityContainer()
   container.AddNewExtension(Of Interception)()
   container.RegisterType(Of Customer)( _
          New Interceptor(Of VirtualMethodInterceptor)(), _
          New InterceptionBehavior(Of NotifyPropertyChangedBehavior)())
柳若烟 2024-10-11 22:47:44

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

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

类定义

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

    public virtual event PropertyChangedEventHandler PropertyChanged;
}

IUnityContainer 设置

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

NotifyPropertyChangedBehavior 修改(原始)

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);
    }
...
}

I need to use the VirtualMethodInterceptor. I found the NotifyPropertyChangedBehavior.Invoke check for a PropertyChanged add or remove was never true. I changed to check for a method name match and things work.

The original NotifyPropertyChangedBehavior is from Unity documentation on msdn. I am interested if anyone can tell me why the original code doesn't work.

Class Definition

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

    public virtual event PropertyChangedEventHandler PropertyChanged;
}

IUnityContainer Setup

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

NotifyPropertyChangedBehavior modification (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);
    }
...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文