Как настроить Unity 2.0 во время выполнения для перехвата INotifyPropertyChanged? - PullRequest
2 голосов
/ 29 ноября 2010

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

Ответы [ 3 ]

2 голосов
/ 30 ноября 2010

Тим

Разве некоторые IL-ткачества не облегчили бы это?

NotifyPropertyWeaver Или http://www.sharpcrafters.com/?

1 голос
/ 29 ноября 2010

Здесь здесь и здесь . В основном, вы должны зарегистрировать тип и перехватчик:

Dim container As IUnityContainer = New UnityContainer()
   container.AddNewExtension(Of Interception)()
   container.RegisterType(Of Customer)( _
          New Interceptor(Of VirtualMethodInterceptor)(), _
          New InterceptionBehavior(Of NotifyPropertyChangedBehavior)())
0 голосов
/ 08 июля 2014

Мне нужно использовать VirtualMethodInterceptor. Я обнаружил, что проверка NotifyPropertyChangedBehavior.Invoke для добавления или удаления PropertyChanged никогда не выполнялась. Я изменил, чтобы проверить соответствие имени метода и все работает.

Оригинальный NotifyPropertyChangedBehavior взят из документации Unity по msdn. Мне интересно, может кто-нибудь сказать мне, почему оригинальный код не работает.

Определение класса

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