views:

54

answers:

1

I am trying to re-create a TypeLoadException for demonstration purposes, so I have a ridiculously goofy library setup that looks like this:

TestProject --> TheLibrary [1.0]
            \-> ProxyForV2 -> TheLibrary [2.0]

TheLibrary version 1 has these relevant interfaces:

public interface IConsistentThing
{
    int ConsistentProperty { get; set; }
}

public interface IShrinkingThing
{
    int RemovedProperty { get; set; }
}

While version 2 of TheLibrary's interfaces look like:

public interface IConsistentThing
{
    int ConsistentProperty { get; set; }
}

public interface IShrinkingThing
{ }

ProxyForV2 has this class which implements the version 2.0 IShrinkingThing:

public class ShrinkingThingImpl : IShrinkingThing
{
    public int ConsistentProperty { get; set; }
}

So, in TestProject, I am expecting to cause a TypeLoadException if someone tries to assign a ProxyForV2.ShrinkingThingImpl, since the first version of the interface has a property that is not implemented by the second version. To prove this, I have a unit test which looks like:

[TestMethod]
public void ShrinkingThingBreaks()
{
    try
    {
        IShrinkingThing thing = new ProxyForV2.ShrinkingThingImpl();

        Assert.Fail("This should have caused a TypeLoadException");
    }
    catch (TypeLoadException)
    {
        //  valid
    }
}

Here's my problem: this unit test fails. But not due to the my Assert.Fail, as I would expect it to. The test output looks like this:

Test method TestProject.LoadTester.ShrinkingThingBreaks threw exception: System.TypeLoadException: Method 'get_RemovedProperty' in type 'ProxyForV2.ShrinkingThingImpl' from assembly 'ProxyForV2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation..

So a TypeLoadException is being thrown and although the only place it could possibly be thrown is in a try block with a catch (TypeLoadException), the exception refuses to be caught. Beyond that, even if I use a catch-all, the unit test fails with the same error as before:

[TestMethod]
public void ShrinkingThingBreaks()
{
    try
    {
        IShrinkingThing thing = new ProxyForV2.ShrinkingThingImpl();

        Assert.Fail("This should have caused a TypeLoadException");
    }
    catch
    {
        //  valid
    }
}

What is going on? Obviously, this is a completely contrived scenario, but I would still like to know what is going on so that this error can be avoided at run time or at least dealt with if it happens (yes, I'm aware the ultimate solution is to make sure all your library versions are the same).

The worst part is that any access to the class at all, such as typeof(ProxyForV2.ConsistentThingImpl) or ProxyForV2.ConsistentThingImpl.SomeStaticFunction() causes this un-catchable TypeLoadException, so it is clear that the problem originates when .NET tries to load the class at all, not from any assignment.

My only idea for mitigating this issue is to try to load the type in a different application domain so that it does not interfere and then do some crazy reflection stuff to see if the interface is compatible with the implementation, but that seems like complete and total overkill.

In summary: Why does it seem impossible to catch this problem in the "normal" way and how can I resolve issues like this at runtime?

+2  A: 

The types get loaded before execution begins on the method that uses them. To do this, you need to:

[TestMethod]
public void ShrinkingThingBreaks()
{
    try
    {
        InnerShrinkingThingBreaks();

        Assert.Fail("This should have caused a TypeLoadException");
    }
    catch
    {
        //  valid
    }
}

[MethodImpl(MethodImplAttributes.NoInlining)]
private void InnerShrinkingThingBreaks()
{
        IShrinkingThing thing = new ProxyForV2.ShrinkingThingImpl();
}
consultutah
Works. It also works by doing the same thing with a lambda function.
Travis Gockel