2010-08-17 89 views
5

我在將對象強制轉換爲生活在另一個庫中的其中一個基礎接口時遇到了問題。下面是它的代碼:將對象強制轉換爲基礎接口

BaseSDK.dll

public interface IPlugin 
{ 
    void Run(); 
} 

CustomPlugin.Definition.dll:

public interface ICustomPlugin 
{ 
    void DoCustomStuff(); 
} 

CustomPlugin.dll(具有參照BaseSDK.dll和CustomPlugin.Definition.dll):

public class CustomPlugin: IPlugin, ICustomPlugin 
{ 
    public void Run() 
    { 

    } 

    public void DoCustomStuff() 
    { 

    } 
} 

Host.exe(有BaseSDK.dll和CustomPlugin.Definition.dll引用):

IPlugin plugin; 
public void DoStuff() 
{ 
    plugin = LoadPluginAndCreateAnInstanceSomehow(); 
    // I know plugin is a CustomPlugin 
    ICustomPlugin customPlugin = plugin as ICustomPlugin; //cast fails. 
    customPlugin.DoCustomStuff(); 
} 

我不明白;這只是簡單的將類型轉換爲基本類型。我怎樣才能解決這個問題?或任何替代品?

編輯:這裏是什麼LoadPluginAndCreateAnInstanceSomehow()做了總結:

Assembly ass = Assembly.LoadFrom(filename); 
Type t = ass.GetType(ass.FullName + ".CustomPlugin"); 
plugin = (IPlugin)Activator.CreateInstance(t); 

編輯2:插件加載到另一個AppDomain中。我不得不在編譯時添加IPlugin和ICustomPlugin.Definiton作爲參考,因爲應用程序必須知道CustomPlugin是什麼樣的。這是問題的根源嗎?如果是這樣,我該如何實現我想要做的?

編輯3:插件加載這樣的:

public class PluginLoader 
    { 
     List<IPlugin> Plugins; 
     AppDomain Domain; 
     string libPath; 
     public void PluginLoader(string sLibPath, AppDomain sDomain) 
     { 

      libPath = sLibPath; 
      Plugins = new List<IPlugin>(); 
      Domain = sDomain; 
      if(Domain==null)Domain = AppDomain.CreateDomain("PluginsDomain"); 
      Domain.AssemblyResolve += new ResolveEventHandler(Domain_AssemblyResolve); 
      Domain.TypeResolve += new ResolveEventHandler(Domain_TypeResolve); 
      Domain.DoCallBack(new CrossAppDomainDelegate(DomainCallback)); 
     } 

     Assembly Domain_AssemblyResolve(object sender, ResolveEventArgs args) 
     { 
      return Assembly.LoadFrom(args.Name); 
     } 
     Assembly Domain_TypeResolve(object sender, ResolveEventArgs args) 
     { 
      return Assembly.LoadFrom(args.Name); 
     } 
     void DomainCallback() 
     { 
      string[] fileNames = Directory.GetFiles(libPath, "*.dll"); 
      foreach (string filename in fileNames) 
      { 

       FileInfo fi = new FileInfo(filename); 
       Assembly ass = Assembly.LoadFrom(fi.FullName); 
       Type t = ass.GetType(ass.FullName + ".CustomPlugin"); 
       IPlugin p = (IPlugin)Activator.CreateInstance(t); 
       Plugins.Add(p); 
      } 
     } 
    }
+1

你能告訴我們你是如何加載到另一個AppDomain插件?我已經嘗試過在各種不同地點的DLL,但我不能複製你的問題。 – Sam 2010-08-18 02:19:36

+2

Assembly ass = Assembly.LoadFrom(fi.FullName)。大聲笑在變量名稱。 – obelix 2010-08-18 03:24:15

+1

我很困惑。爲什麼有人預期從不同應用程序域加載的類型將與當前應用程序域中加載的相同類型兼容? – 2010-08-18 03:28:21

回答

2

我設法重現了這個問題。考慮以下。

假設你的項目有以下運行時的結構(簡化當然)

C:\運行\ - 這是你的主要運行時目錄,有主機。EXE
C:\運行\圖書館\ - 該路徑有你的三個庫組件

的EXE項目引用定義接口的兩個組件,所以它們複製到運行文件夾,但不引用組件包含CustomPlugin,因此不會被複制。

如果項目DID的舊版本引用CustomPlugin.dll並將舊版本複製到\ Runtime會怎麼樣?然後你分開這些。新版本不再被複制,但舊版本仍然存在。

因此,當您從App庫中的AppDomain中創建類時,一切正常,但是當編組回到AppDomain邊界時,主AppDomain需要加載匹配程序集以獲取類型信息。它首先找到舊版本。如果舊版本未實現ICustomConfig,則投射將失敗。你之前提到過他們沒有簽名,所以.NET會爲你犯這個錯誤沒有問題!

所以你的運行目錄包含

Host.exe
BaseSDK.dll
CustomPlugin.Definition.dll
CustomPlugin.dll - 不執行ICustomPlugin

而且你的圖書館目錄舊版本包含

BaseSDK.dll
CustomPlugin.Definition.dll
CustomPlugin.dll - 新版本

編輯

你可以隨時檢查Assembly.Location的plugin.GetType()的值,看看哪些dll被加載在每個AppDomain中。

+0

我刪除了所有東西(bin,lib,tmp.obj等),並從頭開始構建解決方案,所以不會有任何舊版本/新版本的問題。我正在加載到CurrentAppDomain的插件。問題仍然存在:/ – Slantroph 2010-08-18 07:31:58

+0

您是否嘗試查看每個插件的plugin.GetType()。Assembly.Location? – Sam 2010-08-18 23:16:38

+0

我將引用的「Copy Local」屬性設置爲false。現在它就像一個魅力,謝謝! – Slantroph 2010-08-19 02:29:08

1

我不能肯定這是爲什麼發生的,但使用鑄造的「作爲」型,當你沒有得到任何信息當演員失敗。

MSDN文檔說: 「as運算符類似於轉換操作;但是,如果轉換不可行,返回null而不是引發異常。

所以請嘗試使用:

ICustomPlugin customPlugin = (ICustomPlugin)plugin; 

,看看是否存在異常的一些信息,可以幫助解釋爲什麼。

+0

「無法將'CustomPlugin'類型的對象轉換爲'ICustomPlugin'」 – Slantroph 2010-08-17 23:55:25

0

我懷疑這裏有兩種不同的ICustomPlugin類型。例如,如果您正在執行強名稱簽名,並且CustomPlugin.dll加載的HostPlugin.Definition.dll的版本不同於Host.exe加載的版本,則這是可能的。

+0

dll未簽名。並且它們從相同的文件夾加載相同的dll。 – Slantroph 2010-08-18 00:10:11

+1

我同意,這一行非常相關:plugin = LoadPluginAndCreateAnInstanceSomehow();請分享該方法正在做的事情。 – 2010-08-18 00:12:18

+1

當您在Host.exe中對Customoflugin.dll進行評估時,獲得的typeof(ICustomPlugin).AssemblyQualifiedName是什麼? – 2010-08-18 00:17:02

相關問題