簡體   English   中英

獲取包含指定屬性的對象實例

[英]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)以及新值。 因此,我想知道給定一個屬性是否有可能找出它所屬類的實例?

  1. 不要這樣 它破壞了封裝。

  2. 否。在myDataModel.TestValue.Set(2); 擴展方法將始終在屬性返回的值上調用。 無法獲取返回該值的類,實例或屬性。

  3. 您可以執行以下操作:

     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) { ... } } 

    但這是丑陋的,幾乎不可讀,不清楚,效率低下並且容易出錯。

  4. 您正在尋找面向方面的編程(AOP)。

    看看PostSharp或LinFu。

  5. 目前還沒有真正干凈的解決方案來實現INotifyPropertyChanged。 如果鍵入所有屬性設置器工作量太大或容易出錯,則可以使用T4模板生成它們。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM