2012-09-28 36 views
0

我試圖重構一段代碼,並用盡了我能想到的選項。如何實例化一個COM類接口一般

這是原來的代碼,我有:

 if (WebConfigSettings.ComPartition == null && HttpContext.Current != null) 
      Nses = new NSession(); 
     else 
      Nses = (INSession)Marshal.BindToMoniker(string.Format("partition:{0}/new:NuntioServer.NSession", WebConfigSettings.ComPartition)); 

 if (WebConfigSettings.ComPartition == null && HttpContext.Current != null) 
      apses.Wses = new WSession(); 
     else 
      apses.Wses = (IWSession)Marshal.BindToMoniker(string.Format("partition:{0}/new:NuntioServer.WSession", WebConfigSettings.ComPartition)); 

這是怎麼我試圖重構它:
(是的,在C#中,你可以instantiateaninterface

public static TInterface Get<TSubInterface, TInterface>() where TSubInterface: TInterface 
    { 
     <snip></snip> 
     if (!useComPartitions) 
      return Activator.CreateInstance<TSubInterface>(); // --> this is not cooperating 

     return (TInterface)Marshal.BindToMoniker(.....); 
    } 

這是我已經嘗試過:

  1. 我試圖指定新的()約束,然後做一個「新TSubInterface()」: 這將導致生成錯誤:」 ..must是一個非抽象用公共無參數構造函數鍵入,以便將其用作通用類型或方法中的參數'TSubInterface'。「

  2. 當我使用Activator.CreateInstance時,我得到一個運行時異常:」無法創建一個實例接口「

  3. 當我使用Activator.CreateComInstanceFrom(」someAssemblyName「,」t ypeName「),我得到一個編譯錯誤:‘不能轉換表達式類型‘System.Runtime.Remoting.ObjectHandle’返回類型TInterface’

[編輯]我是能夠使加入該編譯'在哪裏TSubInterface:class,但我不確定這是否合理,因爲TSubInterface是一個接口。
使用CreateComInstanceFrom也不起作用,因爲它試圖找到在dll不是並且不應該是的目錄中指定的程序集。

我可以以某種方式使這個編譯和運行?

+0

你使用這個方法的哪個代碼? –

+0

nses = COMUtils.Get () NSession和INSession都是接口。 – TweeZz

+1

你想讓它工作只是因爲你可以或者你打算在生產代碼中使用它?如果另外一個人能夠通過控制容器的反轉來達到類似的目的,那麼他們會更好。 – Rafal

回答

3

您需要關注能夠從接口名稱創建類對象的看似魔術。讓我們挑選一個每個人都可以嘗試的例子。創建一個新的控制檯應用程序並使用Project + Add Reference,Browse選項卡並選擇c:\ windows \ system32 \ shell32.dll。

查看使用Object Browser生成的互操作庫。注意Shell類型是一種接口類型。現在編寫這段代碼:

class Program { 
    static void Main(string[] args) { 
     var shl = new Shell32.Shell(); 
    } 
} 

編譯並在.exe文件上運行ildasm.exe。你會看到:

.method private hidebysig static void Main(string[] args) cil managed 
{ 
    .entrypoint 
    // Code size  8 (0x8) 
    .maxstack 1 
    .locals init ([0] class [Interop.Shell32]Shell32.Shell 'shl') 
    IL_0000: nop 
    IL_0001: newobj  instance void [Interop.Shell32]Shell32.ShellClass::.ctor() 
    IL_0006: stloc.0 
    IL_0007: ret 
} // end of method Program::Main 

注類型名稱如何得到取代從殼牌ShellClass。類型庫導入器創建該類,它使用原始的coclass名稱並將「Class」附加到該名稱。編譯器進行替換。

哪個是關鍵,Activator.CreateInstance()不能進行相同的替換。我沒有看到明確的方式讓泛型進行相同的替換,而不是直接使用IFooClass名稱而不是接口名稱。從技術上講,您可以檢索類型庫導入器應用於接口類型的[CoClass]屬性。

+0

將您的標記標記爲正確,因爲它提出了一個解決方案(使用'CoClass'屬性),並解釋了一些原因並不像我希望的那樣容易 – TweeZz

0

可以搞清楚那是什麼接口的組件類和創造者的一個實例來完成:

var coClassAttribute = type.GetCustomAttribute<CoClassAttribute>(); // our extension method 
return (TSubInterface)Activator.CreateInstance(coClassAttribute.CoClass); 

我並不滿足於此,但它的作品。 (不會將此標記爲正確答案)