2010-06-23 101 views
1

我使用的是第三方組件通過一個靜態類提供的服務:C#'動態'變量可以引用靜態類型嗎?

dynamic lib = new Foo.Bar.NotStaticLibraryClass(); 
lib.Start(); 
var x = lib.GetSomeStuff(); 
lib.Stop(); 

Foo.Bar.StaticLibraryClass.Start(); 
var x = Foo.Bar.StaticLibraryClass.GetSomeStuff(); 
Foo.Bar.StaticLibraryClass.Stop(); 

如果該類不是靜態的,我可以通過一個動態類型的變量使用它的一個實例

不幸的是,這個類是靜態的。有沒有我能寫的東西能讓我以同樣的方式工作?

dynamic lib = /* ??????? */ 
lib.Start(); 
var x = lib.GetSomeStuff(); 
lib.Stop(); 

(爲什麼我使用dynamic變量來訪問一個完美的.NET類型?實際上有庫DLL的多個版本,我必須找出並加載在運行合適的一個。不同的DLL公開了相同的類型和方法名稱,但它們是從任何通用接口繼承而來的,所以如果我能找到一種使用動態類型的方法,它將使我無需編寫大量簡單的反射代碼來使用DLL的方法)

回答

0

對不起,C#動態不直接支持此用法。爲了在C#中調用類方法,您必須直接在源代碼中命名該類型。要做到這一點,你必須參考程序集。動態不會改變這一點。

dynamic does必要時派遣到類方法(例如當您有動態參數時),但即使在上述限制條件的情況下也是如此。

如果目標類型提供了一個可以放入動態變量的實例,那麼你會沒事的。如果你提供了這樣的實例,你會沒事的。或者,如果您將自己的心設置爲動態,則可以編寫自己的IDynamicMetaObjectProvider,以動態方式封裝這些類方法,並給定一個System.Type。至少,如果你想了解DLR,這將是一個有益的項目。

0

c#/ vb.net等是靜態類型語言。因此,如果你有一個沒有Start方法的類型,代碼將不會被編譯。

dynamic關鍵字彌合了靜態語言和動態語言之間的差距。
即是否存在方法,在動態語言的情況下在運行時檢查。

從你的例子中,Start,Stop'GetSomeStuff method exists and your code is aware of it. Moreover, dynamic`與動態加載程序集無關。

我認爲你需要某種插件/提供者類型的模型,其中,你將有一個基類接口,你的實現類將被確認。

例如

interface IService 
{ 
    void Start(); 
    void Stop(); 
    int GetSomeStuff(); 
} 

而實現類(這將是在一個單獨的裝配)將確認爲這個接口,可以裝入動態&投在代碼中這個接口(IService)。

依賴注入/控制反轉是一個概念,我認爲它應該服務於你正在尋找的東西。

+0

動態關鍵字的主要用途是從靜態語言到動態語言或COM對象的橋接,這是正確的。然而它不限於這種用途。例如,我可以編寫以下代碼,它可以正常工作:'dynamic st1 =「test」;動態st2 = st1.ToUpper();字符串st3 = st2.ToString();'我碰巧有一個用例,我需要加載不同版本的程序集,從中我不能要求任何通用接口,即使它們在內部具有相似的類型名稱。使用'dynamic'可以讓我避免大量的手動反射。 – Eric 2010-06-23 15:28:29

+0

@Eric:'dynamic'對於已經加載的類型很有用(我猜)。因此,加載程序集必須手動完成。 創建一個類型的實例(使用'Activator.CreateInstance')並將其分配給一個'dynamic'變量應該有助於這種情況。 – shahkalpesh 2010-06-23 17:57:16

+0

這是一個靜態類型,所以'Activator.CreateInstance'不應該工作... – Eric 2010-06-23 19:36:22

0

使用的dynamic魔力:

using System; 
using System.Dynamic; 
using System.Reflection; 

public class StaticInvoker : DynamicObject 
{ 
    readonly BindingFlags flags; 
    readonly Type type; 

    public StaticInvoker(Type staticType) : this(staticType, false) 
    { 

    } 

    public StaticInvoker(Type staticType, bool nonPublic) 
    { 
     type = staticType; 
     flags = BindingFlags.Static | BindingFlags.Public | (nonPublic ? BindingFlags.NonPublic : 0); 
    } 

    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     try{ 
      result = type.InvokeMember(binder.Name, flags | BindingFlags.GetField | BindingFlags.GetProperty, null, null, null); 
      return true; 
     }catch(TargetInvocationException e) 
     { 
      throw e.InnerException; 
     }catch(MissingMemberException) 
     { 
      result = null; 
      return false; 
     } 
    } 

    public override bool TrySetMember(SetMemberBinder binder, object value) 
    { 
     try{ 
      type.InvokeMember(binder.Name, flags | BindingFlags.SetField | BindingFlags.SetProperty, null, null, new[]{value}); 
      return true; 
     }catch(TargetInvocationException e) 
     { 
      throw e.InnerException; 
     }catch(MissingMemberException) 
     { 
      return false; 
     } 
    } 

    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) 
    { 
     try{ 
      result = type.InvokeMember(binder.Name, flags | BindingFlags.InvokeMethod, null, null, args); 
      return true; 
     }catch(TargetInvocationException e) 
     { 
      throw e.InnerException; 
     }catch(MissingMemberException) 
     { 
      result = null; 
      return false; 
     } 
    } 
} 

dynamic lib = new StaticInvoker(typeof(Foo.Bar.StaticLibraryClass)); 

支持所有的基本操作。