2014-02-17 52 views
-1

保持在屬性我有有一個屬性,又具有Func<object, object>屬性的功能,我想在該屬性更改執行的功能(使用更新後的資產價值爲in T)。這樣做最光滑的方法是什麼?執行後性能變化

注:我知道屬性是靜態並沒有被設計成執行在他們的受讓人改變/ invocaction的事實。我只需要儘可能接近我創建的原型。

一些代碼:

using System; 
using System.Windows; 

namespace AnnotatedBinding 
{ 
    public class AnnotatedPropertyAttribute: Attribute 
    { 
     // static 
     public AnnotatedPropertyAttribute(Func<object, object> evaluator) 
     { 
      Evaluator = evaluator; 
     } 

     public Func<object, object> Evaluator 
     { 
      get; private set; 
     } 
    } 

    public class Test 
    { 
     [AnnotatedProperty(Test.TestEvaluator)] // not compiling!, guess it's fixable by passing in a member info and then calling Reflection Invoke? 
     public string TestProperty 
     { 
      get; set; 
     } 

     public static Func<object, object> TestEvaluator = (x) => MessageBox.Show(x.ToString()); 
    } 

    public class Shell 
    { 
     public void Run() 
     { 
      var test = new Test(); 

      test.TestProperty = "blah";// I want my message box here 

      test.TestProperty = "blah";// and I don't want it here 
     } 
    } 
} 

回答

2

您在TestProperty屬性不編譯因爲代表不允許作爲屬性參數。有關允許哪些類型的詳細信息,請參見this answer from Eric Lippert

關於使用反射的解決方法:由於System.Typestring是有效的屬性參數類型,您當然可以指定擁有該方法的類型以及該屬性中方法的名稱。類似這樣的:

[AnnotatedProperty(typeof(Test), "TestEvaluator")] 
public string TestProperty { get; set; } 

但是,當屬性被設置時,這仍然不會對委託做任何事情。屬性只是元數據,您可以在運行時使用反射(更具體地使用MemberInfo.GetCustomAttributes(...))讀出,分析它們並根據屬性值執行任何操作。這一切都需要手動完成。不幸的是,.NET框架不提供基於應用於成員的屬性自動執行某些操作的功能。這將使財產變更通知的生活變得更加輕鬆。

所以你必須實現手動處理屬性。這意味着,實現getset訪問器,檢查該屬性是否應用於該屬性,確定應該執行的委託並使用反射來執行它。當然,這是沒有意義的,因爲你寧願在setter中添加對方法的調用。

TL;博士:

可能的解決方法:你應該看看PostSharp,圖書館支持在.NET面向方面編程。它可以用於在編譯之後將鍋爐代碼注入方法或其他成員。它通過分析你的MSIL代碼並搜索所謂的「方面」(它們實際上就是你的屬性)來實現這一點。如果找到,它將修改該屬性指定的MSIL。您必須從PostSharp基本屬性/方面派生您的屬性,然後重寫適當的方法。在你的情況下,你將不得不從LocationInterceptionAspect派生,然後重寫OnSetValue(...)方法。在這種方法中,您將使用屬性參數(如上所述)確定委託,然後使用反射調用此參數。 "Intercepting Properties and Fields" in the PostSharp documentation給出了一個很好的介紹如何做到這一點。

我想你最終會是這樣的:

public class ExecuteDelegateOnPropertySetAspect : LocationInterceptionAspect 
{ 
    public ExecuteDelegateOnPropertySetAspect(Type methodOwner, string methodName, object[] arguments) 
    { 
     this.MethodOwner = methodOwner; 
     this.MethodName = methodName; 
     this.Arguments = arguments; 
    } 

    public Type MethodOwner { get; set; } 
    public string MethodName { get; set; } 
    public object[] Arguments { get; set; } 

    public override void OnSetValue(LocationInterceptionArgs args) 
    { 
     // get method with the specified name from the specified owner type 
     MethodInfo method = this.MethodOwner.GetMethod(this.MethodName); 

     // method must be static, otherwise we would need an instance to call it 
     if (method != null && method.IsStatic) 
     { 
      if (method.GetParameters().Length == this.Arguments.Length) 
      { 
       // call the method with the given arguments 
       method.Invoke(null, this.Arguments); 
      } 
     } 

     // execute the original setter code 
     args.ProceedSetValue(); 
    } 
} 

而在你的代碼,你將適用這方面你的屬性:

public class Test 
{ 
    public static void TestMethod(string someMessage) 
    { 
     MessageBox.Show(someMessage); 
    } 

    [ExecuteDelegateOnPropertySetAspect(typeof(Test), "TestMethod", new object[] { "Hello world!" })] 
    public string TestProperty { get; set; } 
} 

注意,我省略大部分的錯誤和空檢查保持簡單和簡短。

+0

愛情http://www.postsharp.net/ – user1514042

0

你似乎有誤解在C#屬性的概念。
屬性具有getter和setter函數。當您設置屬性或獲取其值時,它們會自動執行。

因此,所有你需要做的是你的財產的設定功能更改爲類似這樣:

public class Test 
{ 
    private string _testProperty; 
    private bool testPropertyIsSet = false; 

    public string TestProperty 
    { 
     get { return this._testProperty; } 
     set 
     { 
      _testProperty = value; 
      if (!testPropertyIsSet) 
      { 
       // Do something here when your property gets set for the first time 
      } 
      testPropertyIsSet = true; 
     } 
    } 
} 

然後調用它:

public void Run() 
{ 
    var test = new Test(); 

    test.TestProperty = "blah"; 
    test.TestProperty = "blah2"; 
} 
+0

大聲笑。你似乎已經理解我的問題了 - 這些日子Stacky是如何工作的?以防萬一,如果它不夠清楚 - 我想通過某種原因能夠通過外部評估人員。 – user1514042

+0

@ user1514042:閱讀你的問題,它看起來像你認爲屬性的功能是在設置屬性時以某種方式執行的... –

+0

@Paolo Tedesco我知道:) – user1514042