解决反射时ReflectionTypeLoadException异常
在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)
作者:我也是个傻瓜
出处:http://www.cnblogs.com/liweis/
签名:成熟是一种明亮而不刺眼的光辉。