在question中关于IoC Container的实用性,获奖提交者提到,使用IoC容器,您可以接受:
public class UglyCustomer : INotifyPropertyChanged
{
private string _firstName;
public string FirstName
{
get { return _firstName; }
set
{
string oldValue = _firstName;
_firstName = value;
if(oldValue != value)
OnPropertyChanged("FirstName");
}
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set
{
string oldValue = value;
_lastName = value;
if(oldValue != value)
OnPropertyChanged("LastName");
}
}
}
到此:
var bindingFriendlyInstance = IoC.Resolve<Customer>(new NotifyPropertyChangedWrapper());
问题:
答案 0 :(得分:9)
要使您的第二个代码段有效,NotifyPropertyChangedWrapper
肯定必须使用反射(或dynamic
)来生成一个类,该类提供与Customer
兼容的接口并实现自动属性通知。不应该有任何数据绑定问题,但会有一点开销。
使用动态对象的简化实现可能如下所示:
public class NotifyPropertyChangedWrapper<T>
: DynamicObject, INotifyPropertyChanged
{
private T _obj;
public NotifyPropertyChangedWrapper(T obj)
{
_obj = obj;
}
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
result = typeof(T).GetProperty(binder.Name).GetValue(_obj);
return true;
}
// If you try to set a value of a property that is
// not defined in the class, this method is called.
public override bool TrySetMember(
SetMemberBinder binder, object value)
{
typeof(T).GetProperty(binder.Name).SetValue(_obj, value);
OnPropertyChanged(binder.Name);
return true;
}
// Implement OnPropertyChanged...
}
显然,任何使用其中一个对象的代码都会失去任何静态类型安全性。另一种选择是生成一个实现与被包装的类相同的接口的类。网上有很多这方面的例子。主要要求是您的Customer
必须是interface
,否则它的所有属性都必须是虚拟的。
答案 1 :(得分:3)
以通用方式执行此操作(即实现INotifyPropertyChanged的单个代码 对于任何类)使用代理。有很多实现可以使用Castle.DynamicProxy或LinFu或Unity执行此操作。这些代理库在IoC容器中具有良好的支持,例如DynamicProxy与Castle Windsor的良好集成,Unity拦截(或其他任何调用)与Unity容器明显良好集成。
答案 2 :(得分:2)
我从未使用它,但您可以使用PostSharp创建类似的内容。
答案 3 :(得分:1)
如果您正在寻找自动生成可绑定对象的特定解决方案,您应该查看PropertyChanged.Fody(之前是NotifyPropertyWeaver)。这将重写实现INotifyPropertyChanged的类以包含通知代码。 github页面上有一个例子。
在我看来,这比使用建议的IOC容器解决方案更整洁。但是,它是一个特定于INotifyPropertyChanged绑定的库,因此不适用于一般解决方案,正如您在链接问题中所讨论的那样。