【问题标题】:TypeLoadException hiding inner exceptionTypeLoadException 隐藏内部异常
【发布时间】:2010-10-05 03:40:04
【问题描述】:

我正在使用 Compact Framework 3.5 / VS2008。我对 TypeLoadException 的行为非常奇怪。以下代码会引发此错误。原因是数据库连接有问题。但是,由于某些未知原因,此内部异常丢失并且不包含在 TypeLoadException 中。

try
{
    settingsFromDb = SettingsFromDbManager.Instance;
}
catch (Exception ex)
{
    throw ex; // BREAKPOINT HERE
}

如果我们查看下面的 SettingsFromDbManager 类,可以看出它是一个简单的单例类。 Load() 方法中发生数据库错误。我没有在示例中包含此代码。如果我在下面示例中指示的位置放置一个断点,我会看到一个数据库错误。不幸的是,如果我在上面代码中指示的位置放置一个断点,那么我得到的只是没有内部异常的 TypeLoadException。没有任何迹象表明发生了数据库问题。这很糟糕:(有谁知道为什么会发生这种奇怪的行为??

干杯
标记

public sealed class SettingsFromDbManager
{
    static readonly SettingsFromDbManager _instance = new SettingsFromDbManager(); 

    SettingsFromDbManager()
    {
        try
        {
            Load();
        }
        catch (Exception ex)
        {
            throw ex; // BREAKPOINT HERE
        }
    }

    public static SettingsFromDbManager Instance
    {
        get
        {
            return _instance;
        }
    }

    .... more code ...
}

** 更新**

非常感谢所有伟大的建议和帮助!

皮埃尔我使用了你写的测试类。这是我调用它的代码。我猜这一定是 Compact Framework 的一个怪癖,因为当我检查异常时,它是 TypeLoadException,没有内部异常:(

try
{
    Fail.Test();
}
catch (Exception ex)
{
    var x = ex.ToString(); // BREAKPOINT HERE
}

我认为 VinayC 的原因可能是正确的。这一切都超出了我的认知。不知道现在该怎么办。我不想放弃我的 Singleton 课程——它们很有用。我正在使用来自http://csharpindepth.com/Articles/General/Singleton.aspx 的“第四版”单例模式。我以前没有使用过它们,但在应用程序周围共享一些实用程序类的相同实例而不是多次创建和处置它们似乎是个好主意。性能是 Compact Framework 的一个大问题。

* 更新 *

呜呼!我所要做的就是如下更改 Singleton 类。它在属性 getter 中实例化类。现在我的异常如预期般浮出水面:)

public sealed class SettingsFromDbManager
{
    static SettingsFromDbManager _instance = null; 

    SettingsFromDbManager()
    {
        try
        {
            Load();
        }
        catch (Exception ex)
        {
            throw new Exception("Error loading settings", ex); 
        }
    }

    public static SettingsFromDbManager Instance
    {
        get
        {
            if (_instance == null)
                _instance = new SettingsFromDbManager();

            return _instance;
        }
    }

    .... more code ...
}

【问题讨论】:

  • 类的静态构造函数失败了,这很重要。这通常会生成 TypeInitializationException,对于 CF 可能会有所不同。 TypeLoadException 确实重叠。对我来说,这看起来像是一个 CF 怪癖。对于易碎资源,请避免使用这种模式。
  • 将“throw ex”语句更改为“throw”。 'throw ex' 会重置堆栈跟踪,这可能会造成混乱。
  • 感谢汉斯的评论。您对不那么“不稳定”的单例模式有什么想法吗?
  • 感谢克里斯的提示。我不确定。但这并不能解决问题。
  • 您的解决方案(根本不使用静态构造函数)确实是规避 CF 奇怪行为的方法。很高兴看到您找到了解决方法。

标签: c# windows-mobile exception-handling compact-framework error-handling


【解决方案1】:

据我所知,静态构造函数可能运行在不同的线程上(或者更具体地说是在不同的调用链上)——它从运行时保证它们将在类型被访问之前被调用。静态构造函数中的异常会将类型标记为对应用程序域不可用。访问类型时,您将收到一个 TypeInitializationException (根据文档),但类型构造函数中发生的异常不会作为内部异常出现,因为它不在同一个调用链上 - 就此而言,静态构造函数可能已经执行了很久。正如 Hans 指出的那样,这里唯一的难题是 TypeLoadException 而不是 TypeIntializationException。

编辑:这是article,它解释了类型初始值设定项的惰性/急切语义。您的代码可以是急切的实现(即静态构造函数甚至可能在第一次访问类型字段之前被调用)

【讨论】:

  • @VinayC:从另一个线程抛出异常的假设很有趣;顺便说一句,我的名字是“皮埃尔”,而不是“汉斯”;-)
  • @Pierre,我指的是 Hans Passant 的评论。由于 BeforeFieldInit 语义,CLR 可能会提前运行类型构造函数(然后它必然会发生在不同的线程上)。
  • @VinayC:啊,对不起。我在 cmets 中忽略了 Hans 的回答。
  • 我认为你是对的 VinayC - 谢谢。请查看我添加到问题中的其他 cmets。
  • @Mark,只想指出您的单例实现不是线程安全的。我建议您使用您看到的文章中修改过的第三个版本(使用易失性或内存屏障),或者查看这篇 MSDN 文章中的多线程单例:msdn.microsoft.com/en-us/library/ff650316.aspx。如果冒泡异常并不重要,那么第四/第五版本是最好的单例实现。
【解决方案2】:

没有充分的理由说明静态构造函数中引发的异常不会出现在您的原始调用位置。但是,我不明白为什么你没有得到System.TypeInitializationException,这应该是静态构造函数失败时抛出的异常。

下面是一段示例代码,它抛出 System.TypeInitializationException,内部异常设置为 "failed" 异常:

class Fail
{
    static Fail()
    {
    }

    Fail()
    {
        throw new System.Exception ("failed");
    }

    static readonly Fail instance = new Fail ();

    public static void Test()
    {
    }
}

我会进一步调查以了解为什么您会收到 TypeLoadException,而这应该在程序集无法正确加载或初始化时发生(MSDN 中的TypeLoadException Class)。

【讨论】:

  • 非常感谢皮埃尔的帮助。我已经用一些关于它的 cmets 更新了我的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多