TypeLoadException在try/catch中无法捕获

3
我在尝试重新创建一个TypeLoadException以进行演示,因此我设置了一个非常滑稽的库,看起来像这样:
TestProject --> TheLibrary [1.0]
            \-> ProxyForV2 -> TheLibrary [2.0]

TheLibrary 1版本有以下相关接口:

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

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

TheLibrary 的第二个版本接口如下所示:

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

public interface IShrinkingThing
{ }

ProxyForV2有一个类实现了版本2.0的IShrinkingThing接口:

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

因此,在TestProject中,如果有人尝试分配ProxyForV2.ShrinkingThingImpl,我期望会引发TypeLoadException,因为第一个版本的接口有一个在第二个版本中没有实现的属性。 为了证明这一点,我有一个单元测试看起来像:

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

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

这是我的问题:这个单元测试失败了。但不是因为我的Assert.Fail,这让我感到意外。测试输出如下:

测试方法TestProject.LoadTester.ShrinkingThingBreaks引发异常:System.TypeLoadException:程序集“ProxyForV2,版本=1.0.0.0,Culture=neutral,PublicKeyToken=null”中类型“ProxyForV2.ShrinkingThingImpl”的方法“get_RemovedProperty”没有实现。

所以一个TypeLoadException被抛出,虽然它唯一可能被抛出的地方是在一个带有catch(TypeLoadException)try块中,但异常却无法被捕获。此外,即使我使用一个捕获所有异常的语句,单元测试仍然以前面相同的错误失败。
[TestMethod]
public void ShrinkingThingBreaks()
{
    try
    {
        IShrinkingThing thing = new ProxyForV2.ShrinkingThingImpl();

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

发生了什么?显然,这是一个完全虚构的场景,但我仍然想知道发生了什么,以便可以在运行时避免此错误或至少处理它(是的,我知道最终的解决方案是确保所有库版本都相同)。
最糟糕的部分是,任何对该类的访问,例如typeof(ProxyForV2.ConsistentThingImpl)或ProxyForV2.ConsistentThingImpl.SomeStaticFunction()都会导致这个无法捕获的TypeLoadException,因此很明显问题源自于.NET尝试加载类时,而不是任何赋值操作。
我唯一缓解此问题的想法是尝试在不同的应用程序域中加载类型,以便它不会干扰,然后进行一些疯狂的反射操作,以查看接口是否与实现兼容,但这似乎是完全过度的。
总之:为什么似乎无法以“正常”的方式捕获此问题,并且如何在运行时解决此类问题?

1
不是很确定,只是评论一下...单元测试的类型不是都会在前面加载吗?所以TypeLoadException实际上是在你甚至进入try/catch块之前抛出的。虽然我不确定你怎么测试这个... - Jaymz
这个类中还有其他单元测试通过得非常好。如果你的意思是方法中使用的类型在方法调用时加载,那可能是问题的根源。 - Travis Gockel
1个回答

7

在使用类型的方法开始执行之前,需要加载这些类型。为此,您需要执行以下操作:

[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();
}

1
可以工作。使用lambda函数执行相同的操作也可以工作。 - Travis Gockel
@TravisGockel 有使用 lambda 函数的示例吗? - Kiquenet
@Kiquenet:由于已经过去了4年,我不太记得清楚了,但我想在try块内部,我大概是这样说的:“Action f = delegate () { var x = new ProxyForV2.ShrinkingThingImpl(); }; f();”。 - Travis Gockel
@TravisGockel 很好的技巧关于lambda函数!它让你实现一个内联解决方案。 - Joel Malone
谢谢您的解答;这解释了为什么我的静态构造函数会抛出异常,即使我已经在其中用try-catch包围了一切!我知道在静态构造函数中做太多事情是不好的,现在我有了一个额外的理由来避免在这种情况下进行“复杂”的初始化... - Ian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接