这个问题可能需要一段时间来解释,我需要提供背景......
这只是我正在玩的东西而不是用于制作,但目前我有一些看起来像这样的代码:
var myDataModel = new DataModel();
myDataModel.PropertyChanged += myDataModel_PropertyChanged;
myDataModel.ChangeProperty(t => t.TestValue, 2);
因此,我不是直接使用myDataModel.TestValue = 2
,而是使用ChangeProperty
扩展方法,以便我可以处理所有更改事件并在一个地方执行任何我想要的操作。我的扩展方法看起来像这样(是的,我知道它是hacky):
public static class NotifyPropertyChangedExtensions
{
public static void ChangeProperty<T, U>(
this T instance,
Expression<Func<T, U>> propertyToChange,
U newValue)
{
var member = propertyToChange.Body as MemberExpression;
if (member != null)
{
if (!propertyToChange.Compile().Invoke(instance).Equals(newValue))
{
var setProperty = instance.GetType().GetProperty(
member.Member.Name,
BindingFlags.SetProperty |
BindingFlags.Public |
BindingFlags.Instance);
if (setProperty != null)
{
// actually set the property
setProperty.SetValue(instance, newValue, null);
// raise the property changed event
if (typeof(INotifyPropertyChanged).IsAssignableFrom(
typeof(T)))
{
var delegatesToCall =
instance.GetType().GetField("PropertyChanged",
BindingFlags.Instance |
BindingFlags.NonPublic)
.GetValue(instance) as MulticastDelegate;
if (delegatesToCall != null)
{
var eventArgs = new PropertyChangedEventArgs(
setProperty.Name);
foreach (var @delegate in
delegatesToCall.GetInvocationList())
{
@delegate.Method.Invoke(
@delegate.Target,
new object[] { instance, eventArgs });
}
}
}
}
}
}
else
{
throw new ArgumentException(
string.Format(
"Cannot determine the property to change {0}",
propertyToChange));
}
}
}
使用这种架构,我的数据模型非常干净:
public class DataModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int TestValue { get; set; }
}
也就是说,我可以使用自动属性,而不必担心引发事件等。
现在,我真正想做的是接近这一点:
var dataModel = new DataModel();
myDataModel.PropertyChanged += myDataModel_PropertyChanged;
myDataModel.TestValue.Set(2); // this is what I want...
所以,我认为我基本上需要一个扩展方法 - 但我只能看到如何发送属性本身(本例中为TestValue)和新值。那么我想知道给定一个属性是否有可能找出它所属的类的实例?
答案 0 :(得分:1)
不要这样做。它破坏了封装。
没有。在myDataModel.TestValue.Set(2);
中,将始终对属性返回的值调用扩展方法。无法获取返回值的类,实例或属性。
你可以这样做:
var t = new DataModel();
((Expression<Func<int>>)(() => t.Foo)).Set(100);
与
static class Extensions
{
public static void Set<T>(this Expression<Func<T>> expression, T value)
{ ... }
}
但这很难看,几乎不可读,不清楚,效率低下且容易出错。
您正在寻找面向方面编程(AOP)。
查看PostSharp或LinFu。
实现INotifyPropertyChanged还没有真正干净的解决方案。如果键入所有属性设置器太多工作或太容易出错,我会使用T4模板生成它们。