public class Foo { public virtual int Id { get; set; } public virtual string Name { get; set; } }
PM> Install-Package Unity.Interception
namespace NotifyPropertyChangedInterceptor.Interceptions { using System; using System.Collections.Generic; using System.ComponentModel; using System.Reflection; using Microsoft.Practices.Unity.InterceptionExtension; class NotifyPropertyChangedBehavior : IInterceptionBehavior { private event PropertyChangedEventHandler PropertyChanged; private readonly MethodInfo _addEventMethodInfo = typeof(INotifyPropertyChanged).GetEvent("PropertyChanged").GetAddMethod(); private readonly MethodInfo _removeEventMethodInfo = typeof(INotifyPropertyChanged).GetEvent("PropertyChanged").GetRemoveMethod(); public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { if (input.MethodBase == _addEventMethodInfo) { return AddEventSubscription(input); } if (input.MethodBase == _removeEventMethodInfo) { return RemoveEventSubscription(input); } if (IsPropertySetter(input)) { return InterceptPropertySet(input, getNext); } return getNext()(input, getNext); } public bool WillExecute { get { return true; } } public IEnumerable<Type> GetRequiredInterfaces() { yield return typeof(INotifyPropertyChanged); } private IMethodReturn AddEventSubscription(IMethodInvocation input) { var subscriber = (PropertyChangedEventHandler)input.Arguments[0]; PropertyChanged += subscriber; return input.CreateMethodReturn(null); } private IMethodReturn RemoveEventSubscription(IMethodInvocation input) { var subscriber = (PropertyChangedEventHandler)input.Arguments[0]; PropertyChanged -= subscriber; return input.CreateMethodReturn(null); } private 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 subscribers = PropertyChanged; if (subscribers != null) { subscribers(input.Target, new PropertyChangedEventArgs(propertyName)); } return getNext()(input, getNext); } } }
var container = new UnityContainer(); container.RegisterType<Foo, Foo>( new AdditionalInterface<INotifyPropertyChanged>(), new Interceptor<VirtualMethodInterceptor>(), new InterceptionBehavior<NotifyPropertyChangedBehavior>()) .AddNewExtension<Interception>();
- Interceptor : اطلاعاتی در مورد IInterceptor و نحوهی Intercept یک شیء را نگه داری میکند. در اینجا از VirtualMethodInterceptor برای تزریق کد استفاده شده.
- InterceptionBehavior : این کلاس Behavior مورد نظر را به کلاس تزریق میکند.
- AddintionalInterface : کلاس target را مجبور به پیاده سازی اینترفیس دریافتی از پارامتر میکند. اگر کلاس behavior، متد GetRequiredInterfaces اینترفیس INotifyPropertyChanged را برمی گرداند، نیازی نیست از AddintionalInterface در پارامتر متد فوق استفاده کنید.
نکته : کلاس VirtualMethodInterceptor فقط اعضای virtual را تحت تاثیر قرار میدهد.
var foo = container.Resolve<Foo>(); (foo as INotifyPropertyChanged).PropertyChanged += FooPropertyChanged; private void FooPropertyChanged (object sender, PropertyChangedEventArgs e) { // Do some things....... }