2013-02-11 63 views
7

我正在使用expando對象,並試圖定義計算屬性。在expando對象上定義計算屬性

我知道我可以做類似下面的定義簡單的屬性:

dynamic myExpando = new ExpandoObject(); 
myExpando.TheAnswerToLifeTheUniverseAndEverything= 42; 

同樣,我也可以定義一個方法:

myExpando.GetTheQuestion = ((Func<string>)(() => 
     { 
      return "How many road must a man walk down before we can call him a man?"; 
     })); 

與標準對象工作時,我們可以定義一個計算的屬性,即定義一個屬性,該屬性將返回自定義方法/計算的結果。不需要舉例。

我需要在我的expando上做類似的事情 - 擁有一個實際調用「Func」(或某種其他形式的委託,只要我可以調用自定義方法並具有自定義返回類型就會發生的任何屬性) 。所以基本上我需要像第二個例子那樣調用一個方法,但是它的工作方式就像一個屬性。

基本上,我需要能夠與myExpando.GetTheQuestion而不是myExpando.GetTheQuestion()調用它,同時保持定義自定義委託的物業體的能力。

有沒有辦法做到這一點?我相信我可以通過使用表達式樹,但我承認我有點迷路了。任何人都可以提供一些如何實現這一目標的指導?


編輯

做了一些更多的研究。除非有一些非常具體的類/接口/ sintax,我不知道我開始認爲上述是不可能的。從我得到的結果來看,ExpandoObject類通過定義一些做後臺管道的方法來工作 - TryGetMember,TrySetMember等等。 現在,當在動態objetc上「訪問屬性」時,TryGetMember就是被調用的記憶。該成員從一個內部字典返回一個值(是的,我知道...這是一個簡單的但應該給出的想法)...沒有測試返回的值的類型。這意味着在我的例子myExpando.GetTheQuestion將返回原來的Func。

似乎是因爲TryGetMember只是返回一個值,所以沒有辦法讓它「執行」屬性代碼。爲了達到這個目的,你需要一些表達式/ lambda/func/action代理,這個值實際上是方法的結果。這似乎是不可能的(除非我錯過了某些東西 - 也就是說,這樣做會有多大意義 - 基本上你會有一個設置爲'委託'的值,然後得到委託返回值?)。我正確或這或我錯過了什麼?

回答

2

你需要讓自己ExpandoObject,通過繼承DynamicObject和壓倒一切的

public override bool TryGetMember(GetMemberBinder binder, out object result)public override bool TrySetMember(SetMemberBinder binder, object value)

實施TrySetMember的值在私人Dictionary<string,object>存儲binder.Name下,並使用TryGetMember從該字典檢索,這會給你一個基本的ExpandoObject。然後給它你需要的功能,在TryGetMember上添加一個檢查,在你拉出對象之後,看看它是否爲,然後用反射來看它是否沒有任何參數。如果兩者都爲真,則轉換爲dynamic並且不添加arg調用括號並將其分配給result

public override bool TryGetMember(GetMemberBinder binder, out object result) 
{ 
     if (_dictionary.TryGetValue(binder.Name, out result)){ 
      if(result is Delegate && /* some reflection check on args*/){ 
       result = ((dynamic)result)(); 
      } 
     } 
} 

我有了一個開源框架ImpromptuInterface(中的NuGet)一非密封ImpromptuDictionary,你就可以像你ExpandoObject代替,特別是如果你需要任何的ExpandoObject這樣的更細緻的功能啓動作爲gui綁定支持。它也有更多的dlr plumbing features,你可能會覺得有用。

+0

是的,其實我雖然有關類似的解決方案 - 但我想知道如果沒有自定義代碼(不是我不能添加它 - 所有我的expando對象已經是一個自定義繼承類),這應該是可能的通過使用表達式樹木等。無論如何,如果沒有其他方式會發布,我會接受這是最合適的^ _^ – SPArchaeologist 2013-02-12 08:41:17

+0

好吧,現在我會接受這一點。這是一種解決方法,但我想這也是讓「計算屬性」像普通屬性一樣行爲的唯一方法。因爲我已經擴展了基礎expando來支持其他行爲(我使用了一個安全的expando,它爲未定義的屬性返回null),我想我可以用這個(實際上這是我的第一個想法,但我發佈了問題,無論如何看到如果我錯過了什麼)。感謝jbtule,我也會看看你的lib - 總有一些東西需要學習。 – SPArchaeologist 2013-02-12 15:44:03