2012-11-28 65 views
3

我有一個動態的變量C#動態執行函數的名字?

dynamic d = GetSomeObject();

有時,在未來,用戶給我一個函數來執行(其name)如"UsersGetAll"

所以我需要做的是這樣的:d.UsersGetAll()

我可以用反射來做到這一點。但我想使用DLR。

做這個的唯一解決方案是從DynamicObject繼承MyObject,然後執行TryInvokeMember

如果我無法控制課程該怎麼辦?

+0

什麼是想要使用DLR的原因是什麼? AFAIK「動態」語言功能旨在簡化對未知對象的已知方法調用。也許在運行時生成由Roslyn編譯的代碼? – flindeberg

回答

1

正如Jon指出的那樣,如果您懷疑類型是在運行時通過DLR提供方法,在最簡單的情況下,反思會更容易。

dynamic僅用於知道方法名稱但不知道目標的情況。如果你不知道方法名稱,它就是比較費力的。棘手的問題也許在於確保您保持呼叫站點的地位,以便可以重複使用(這是DLR保持性能的方式)。一個厚顏無恥的方式將是一個靜態的工具類,跟蹤調用的方法。這裏有一個例子 - 請注意,它得到混亂,如果你需要處理的參數:

using Microsoft.CSharp.RuntimeBinder; 
using System; 
using System.Collections; 
using System.Runtime.CompilerServices; 
public class Foo 
{ 
    public object Bar() { return "I was here"; } 
} 
static class Program 
{ 
    static void Main() 
    { 
     object obj = new Foo(); 
     object result = DynamicCallWrapper.Invoke(obj, "Bar"); 
     Console.WriteLine(result); 
    } 
} 

static class DynamicCallWrapper 
{ 
    // Hashtable has nice threading semantics 
    private static readonly Hashtable cache = new Hashtable(); 
    public static object Invoke(object target, string methodName) 
    { 
     object found = cache[methodName]; 
     if (found == null) 
     { 
      lock (cache) 
      { 
       found = cache[methodName]; 
       if(found == null) 
       { 
        cache[methodName] = found = CreateCallSite(methodName); 
       } 
      } 
     } 
     var callsite = (CallSite<Func<CallSite, object,object>>)found; 
     return callsite.Target(callsite, target); 
    } 
    static object CreateCallSite(string methodName) 
    { 
     return CallSite<Func<CallSite, object, object>>.Create(
      Binder.InvokeMember(
      CSharpBinderFlags.None, methodName, null, typeof(object), 
      new CSharpArgumentInfo[] { 
       CSharpArgumentInfo.Create(
        CSharpArgumentInfoFlags.None, null) })); 

    } 
} 
1

我可以用反射來做到這一點。但我想使用DLR。

爲什麼?假設這是一個實際上不會動態響應的「正常」對象,反射將成爲這裏最簡單的方法。

C#4中的dynamic功能(根據語言功能)在這裏完全沒有任何幫助。它只允許在C#源代碼內動態綁定成員名稱

現在你

  • 啓動IronPython的會話,並創建一個微小的Python腳本使用動態綁定來調用方法。
  • 使用CSharpCodeProvider以相關方法名稱使用dynamic編譯一些C#代碼,然後執行該代碼。
  • 看看你的d.UsersGetAll()調用生成的代碼,並基本上模擬。

所有這些選項都可能比反射更困難,如果所有你想要它,所以調用一個「普通」對象的「正常」方法,並且你恰好只知道執行時的名字。