解决反射时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)

c# 用代码来设置程序的PrivatePath_夏仲达的博客-CSDN博客_privatepath

posted @ 2021-06-12 13:04  我也是个傻瓜  阅读(2554)  评论(0编辑  收藏  举报