在GIS開發程序中,為了增加擴展性,往往采用插件式開發模式,自然用到了反射技術。如果反射使用的dll控制不好,很容易引發反射異常,查找原因十分不方便,可以使用PrettyBin或Costura等組件實現對類庫的管理。
問題描述
使用主程序Main.exe反射調用A.dll文件時,出現"未處理 System.Reflection.ReflectionTypeLoadException Message="無法加載一個或多個請求的類型。有關更多信息,請檢索LoaderExceptions屬性。",代碼如下:
var assembly = Assembly.LoadFile(filePath); var types= assembly.GetTypes(); //引發ReflectionTypeLoadException異常
進一步查看LoaderExceptions異常,發現是因為缺少B.dll或它的某一個依賴項。
未能加載文件或程序集"B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"或它的某一個依賴項。系統找不到指定的文件。
A.dll確實引用了B.dll,但仔細核對和檢查了所有dll文件都在A.dll所在目錄,沒有發現缺失的情況。
這種錯誤一般只有兩種原因:一是dll文件不能被調用主程序找到,二是dll文件能找到,但版本不對。實際上,B.dll和A.dll雖然是在相同目錄,但與Main.exe不同,使用Main.exe反射調用其他算子時,它只會在Main.exe所在目錄 去找B.dll,當然找不到,所以報錯。
解決方案
方法一: AssemblyResolve事件
一種解決方法是注冊當前域(AppDomain.CurrentDomain)的AssemblyResolve事件,即當反射調用A.dll文件時,它找不到B.dll,就會觸發此事件,在這個事件中手動找路徑。這種方法的缺點時,需要手動指定路徑,不方便修改。
方法二: privatePath配置
為了動態修改目錄,可直接在AppConfig配置中指定dll所在的目錄,如下:
<configuration> ….. <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="目錄1; 目錄2" /> </assemblyBinding> </runtime> </configuration>
當程序在exe所在的目錄找不到dll時,它會依次在目錄1、目錄2中找,如果還找不到就報錯!
當然也可以用代碼來實現,自動添加軟件目錄下所有文件夾作為privatePath的值。
參考連接
關於跨程序集的反射 - torome - 博客園 (cnblogs.com)
AppDomain.CurrentDomain.AssemblyResolve - mCat - 博客園 (cnblogs.com)