How to reproducably cause / provoke a ReflectionTypeLoadException?

前端 未结 2 581
时光取名叫无心
时光取名叫无心 2020-12-11 23:06

Sadly, references to this exception are usually of an exotic nature and can happen when you e.g. enumerate Types via Assembly.GetTypes() - case in point, it is

相关标签:
2条回答
  • 2020-12-11 23:57

    The following causes this exception:

    You have assembly A which defines the following class:

    public class AC
    {
        public BC GetBC() { /* ... */ }
    }
    

    You have assembly B which defines the class BC. Now, when you load Assembly A and get the members of class AC, for example using assembly.GetTypes().SelectMany(t => t.GetMembers()).ToList();, the framework tries to resolve BC. It even knows that it is in assembly B. However, if the framework resolves an assembly B that doesn't contain BC, a TypeLoadException will be thrown. This can happen, if assembly B is not up-to-date, because you forgot it in your deployment.

    UPDATE:
    To actually get a ReflectionTypeLoadException, the scenario is very similar. However, you don't need to have a method in AC that returns BC but you need to derive AC from BC:

    public class AC : BC
    {
    }
    

    Using the LoaderExceptions property, you can retrieve the exceptions that lead to this ReflectionTypeLoadException. In my case, this is a TypeLoadException stating exactly what type it couldn't load.

    0 讨论(0)
  • 2020-12-12 00:00

    Another approach if you wish to test how your code handles the exception is to use mocking in your testing. With mocking you can mock out the assembly loading sub-system and concentrate on testing how you handle the resulting exception - much more straight-forward.

    Using mocking you would use an IAssemblyService instead of calling GetTypes on Assembly directly. In your mock you can throw the required exception. It is more usual to use a mocking framework such as FakeItEasy, but the following uses a hand-rolled mock for demonstration.

    In your test you would substitute your real assembly service with 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();
        }
    }
    

    And with a mocking framework such as 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...
    }
    
    0 讨论(0)
提交回复
热议问题