遗憾的是,引用此异常通常具有奇异的性质,并且可能在您例如通过Assembly.GetTypes()
枚举类型时发生-例如,它发生在我们的一个部署中,但同一组程序集在集成服务器上运行良好。
为了防止这种类型的错误,我希望能够触发这样一个异常,看看我的异常处理代码是否按预期工作。
因此,任何指针都是有用的,例如,只要知道是什么样的东西导致了这个异常。
<罢工> 编辑我的尝试到目前为止:罢工>
- 在程序集a中定义使用程序集B的属性的类型
- 让一些代码遍历程序集中所说的所有类型属性。
- 我只在DEBUG标志为true时构建属性 然后将该依赖项的发布版本复制到相关文件夹
但我只设法得到一个TypeLoadException
与一个非常明确的错误信息
导致此异常的原因如下:
程序集A定义了以下类:
public class AC
{
public BC GetBC() { /* ... */ }
}
程序集B定义了类BC
。现在,当您加载汇编A并获取类AC
的成员时,例如使用assembly.GetTypes().SelectMany(t => t.GetMembers()).ToList();
,框架将尝试解析BC
。它甚至知道它在汇编B
中。但是,如果框架解析的程序集B
不包含BC
,则会抛出TypeLoadException
。如果程序集B
不是最新的,因为您在部署中忘记了它,就会发生这种情况。
更新:
要实际获得ReflectionTypeLoadException
,情况非常相似。然而,你不需要在AC
中有一个返回BC
的方法,但你需要从BC
中派生AC
:
public class AC : BC
{
}
使用LoaderExceptions
属性,您可以检索导致此ReflectionTypeLoadException
的异常。在我的例子中,这是一个TypeLoadException
,说明它不能加载什么类型
如果您希望测试代码如何处理异常,另一种方法是在测试中使用mock。使用mock,您可以模拟程序集加载子系统,并专注于测试如何处理产生的异常——更加直接。
使用mock,您将使用IAssemblyService
而不是直接在Assembly
上调用GetTypes
。在模拟中,可以抛出所需的异常。使用像FakeItEasy这样的模拟框架更为常见,但下面使用手工制作的模拟进行演示。
在您的测试中,您将用MockAssemblyService
代替您的实际组装服务。
internal class MyTypeThatLoadsStuff
{
public MyTypeThatLoadsStuff(IAssemblyService assemblyService)
{
//Do stuff with assemblyService
}
}
internal interface IAssemblyService
{
IEnumerable<Type> GetTypes();
}
internal class AssemblyService : IAssemblyService
{
private readonly Assembly _assembly;
public AssemblyService(Assembly assembly)
{
_assembly = assembly;
}
public IEnumerable<Type> GetTypes()
{
return _assembly.GetTypes();
}
}
internal class MockAssemblyService : IAssemblyService
{
public IEnumerable<Type> GetTypes()
{
throw new ReflectionTypeLoadException();
}
}
和一个mock框架,如FakeItEasy:
[Test]
public void Test()
{
IAssemblyService service = A.Fake<IAssemblyService>();
ReflectionTypeLoadException ex = new ReflectionTypeLoadException(
new[] { typeof(SprocketTests) }, new[] { new Exception() });
A.CallTo(() => service.GetTypes()).Throws(ex);
MyTypeThatLoadsStuff loader = new MyTypeThatLoadsStuff(service);
//test...
}