2009-12-18 146 views
8

是的,標題聽起來有點令人困惑,所以我會解釋我的意思:假設你有一個C#4.0'動態'對象和一個屬性的名稱。你將如何從動態對象中檢索該屬性?動態獲取動態對象的值

換句話說,你將如何實現:

public static object GetDynamicValue(dynamic o, string name) { ... } 

另一種方式把它就是我試圖把一個動態的對象作爲一個IDictionary。

請注意,由於動態對象可能是一種不基於反射的自定義實現(例如通過擴展DynamicObject並執行自己的操作),因此反射可能不是此處的選項。

+1

你能告訴更多一點關於你的使用情況?如果你想有一個類似於IDictionary的動態對象,爲什麼不使用ExpandoObject呢?喬恩的建議可能有效,但我有一種感覺,這對於你想要做的事情來說太複雜了。 – 2009-12-18 18:56:55

回答

13

你必須建立一個呼叫的網站,創建一個粘結劑等

看看會發生什麼,最簡單的方法是編譯這樣的:用反射

public static object GetDynamicValue(dynamic o, string name) 
{ 
    return o.Foo; 
} 

然後反編譯,並制定出什麼它在做。它會非常複雜,介意你 - 你需要將它從一個單一的,靜態的,緩存的調用站點改變爲在每次調用時創建一個新站點。

下面是該做的工作的例子...但無論是完全正確與否是另一回事:)(我這做什麼我上面建議去。)

using Microsoft.CSharp.RuntimeBinder; 
using System; 
using System.Dynamic; 
using System.Runtime.CompilerServices; 

class Test 
{ 
    public static object GetDynamicValue(dynamic o, string name) 
    { 
     CallSite<Func<CallSite, object, object>> site 
      = CallSite<Func<CallSite, object, object>>.Create 
      (Binder.GetMember(CSharpBinderFlags.None, name, 
      typeof(Test), new CSharpArgumentInfo[] 
      { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) })); 
     return site.Target(site, o); 
    } 

    static void Main() 
    { 
     Console.WriteLine(GetDynamicValue("hello", "Length")); 
    } 
} 
+0

非常好,謝謝喬恩!這帶來了很多我沒有處理的概念,所以我需要仔細研究它。 感覺很奇怪,typeof(Test)在那裏被使用,因爲它應該是沒有關係的。但我試着將它設置爲null,並且代碼仍然有效,所以顯然它沒有太大的作用。 – 2009-12-18 07:33:51

+3

它與哪些成員可訪問有關 - 您可以使用此代碼獲取Test的私有成員,但不能使用其他類型的私有成員。 – 2009-12-18 08:05:17

3

的開源框架ImpromptuInterface(可在nuget中使用)執行此操作,並執行額外的工作,因爲緩存呼叫站點對性能很重要。

InvokeGet

​​
+0

粘土也是這樣(http://clay.codeplex.com/) – 2011-03-15 04:57:49

+0

@ David-Ebbo雖然Clay允許您通過字符串名稱訪問它自己的屬性,但是「InvokeGet」允許您通過字符串名稱訪問任何IDynamicMetaObjectProvider屬性(或任何規則的對象更快的反射)...除非我失去了一些東西。 – jbtule 2011-03-15 12:48:35