[英]Get the object instance which contains a specified property
這個問題可能需要一段時間才能解釋,我需要提供背景知識...
這只是我正在玩的東西,而不是用於生產,但是目前我有一些看起來像這樣的代碼:
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)以及新值。 因此,我想知道給定一個屬性是否有可能找出它所屬類的實例?
不要這樣 它破壞了封裝。
否。在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模板生成它們。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.