前回と同じのりでINotifyPropertyChangedも実装できますよっと。IDataErrorInfoの例は、基本クラス用意して継承したほうが断然いいと思いますがINotifyPropertyChangedを実装してプロパティにいちいちイベント発行コードかくのだるいので、こっちのほうがありがたみあるかもしれません。
ということでコード
using System; using System.Data.Common; using System.Linq; using System.Linq.Expressions; using Microsoft.Practices.EnterpriseLibrary.Common.Configuration; using Microsoft.Practices.EnterpriseLibrary.Data; using Microsoft.Practices.EnterpriseLibrary.Validation; using System.ComponentModel; using Microsoft.Practices.Unity.InterceptionExtension; using System.Collections.Generic; using System.Reflection; using Microsoft.Practices.Unity; namespace ConsoleApplication4 { public class Person : INotifyPropertyChanged { public virtual event PropertyChangedEventHandler PropertyChanged; protected virtual void RaisePropertyChanged(string name) { if (this.PropertyChanged != null) { this.PropertyChanged(this, new PropertyChangedEventArgs(name)); } } public virtual string Name { get; set; } private int age; public int Age { get { return age; } set { this.age = value; this.RaisePropertyChanged("Age"); this.RaisePropertyChanged("Name"); } } } public class NotifyPropertyChangedBehavior : IInterceptionBehavior { private static readonly EventInfo PropertyChangedEventInfo = typeof(INotifyPropertyChanged).GetEvent("PropertyChanged"); private event PropertyChangedEventHandler handler; public IEnumerable<Type> GetRequiredInterfaces() { yield return typeof(INotifyPropertyChanged); } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { if (input.MethodBase.Name == PropertyChangedEventInfo.GetAddMethod().Name) { var d = input.Arguments[0] as PropertyChangedEventHandler; this.handler += d; return getNext()(input, getNext); } if (input.MethodBase.Name == PropertyChangedEventInfo.GetRemoveMethod().Name) { var d = input.Arguments[0] as PropertyChangedEventHandler; this.handler -= d; return getNext()(input, getNext); } if (input.MethodBase.IsSpecialName && input.MethodBase.Name.StartsWith("set_")) { var result = getNext()(input, getNext); var name = input.MethodBase.Name.Substring(4); if (this.handler != null) { this.handler(input.Target, new PropertyChangedEventArgs(name)); } return result; } return getNext()(input, getNext); } public bool WillExecute { get { return true; } } } class Program { static void Main(string[] args) { var c = new UnityContainer(); c.AddNewExtension<Interception>(); c.RegisterType<Person>( new Interceptor<VirtualMethodInterceptor>(), new InterceptionBehavior<NotifyPropertyChangedBehavior>()); var p = c.Resolve<Person>(); p.PropertyChanged += (_, e) => Console.WriteLine(e.PropertyName); p.Name = "a"; p.Name = "bbb"; p.Age = 10; } } }
virtualをつけたプロパティのsetを横取りしてます。virtualをつけなければ自分で全部実装すればOKというノリです。まぁこういうことやるとUnityにインスタンス生成を任せないといけないので、そういう縛りは出てきちゃうのでちょっと嫌な感じもありますね。
ということで、こういうことをやるときは、きちんと破綻しないことを確信してからやるのがいいと思います。以上マル。