如何在运行时配置Unity 2.0来拦截INotifyPropertyChanged?
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
Tim
一些 IL 编织不会让这件事变得更容易吗?
NotifyPropertyWeaver 或 http://www.sharpcrafters.com/?
Tim
Wouldn't some IL weaving make this easier?
NotifyPropertyWeaver Or http://www.sharpcrafters.com/ ?
位于此处和此处。基本上,您必须注册类型和拦截器:
It's here and here. Basically, you have to register the type and the interceptor:
我需要使用 VirtualMethodInterceptor。我发现 NotifyPropertyChangedBehavior.Invoke 检查 PropertyChanged 添加或删除从来都不是真的。我更改为检查方法名称匹配并且一切正常。
原始的 NotifyPropertyChangedBehavior 来自 msdn 上的 Unity 文档。我很感兴趣是否有人能告诉我为什么原始代码不起作用。
类定义
IUnityContainer 设置
NotifyPropertyChangedBehavior 修改(原始)
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
IUnityContainer Setup
NotifyPropertyChangedBehavior modification (original)