静态构造函数中的异常

Jam*_*ing 33 c# constructor exception static-classes

我在SO周围挖了一个答案,到目前为止我能找到的最好的是这里,但是这是针对静态构造函数的实例; 我只是静态使用这个类.

我的代码:

public static class MailHelper {

    private static string mailHost;

    static MailHelper() {

        var mailSettings = ConfigurationManager.GetSection("MailSettings") as NameValueCollection;
        if (null == mailSettings) {
            throw new ConfigurationErrorsException("Missing Mail Settings in the configuration file");
        }

        mailHost = ConfigurationManager.AppSettings["mailHost"];
        if (null == mailHost) {
            throw new ConfigurationErrorsException("Missing mailHost setting in the configuration file");
        }

    }

    public static void SendMail(MailMessage Message) {
        ...
    }

}


try {
    MailHelper.SendMail(Message);
}
catch (ConfigurationErrorsException exc) {
    ...
}

//  ???    
MailHelper.SendMail(Message);


.
Run Code Online (Sandbox Code Playgroud)

因此,如果静态构造函数在第一次调用时抛出异常,那么第二次尝试访问静态SendMail()方法时会发生什么?

PS:对不起,如果你不喜欢Stroustrup的K&R支架造型版本,但是不要编辑我的帖子只是为了将支架更改为你喜欢的Allman风格.谢谢.

Jon*_*eet 91

类型初始值设定项失败一次后,永远不会重试.该类型在AppDomain的生命周期内已经死亡.(请注意,对于所有类型初始值设定项都是如此,不仅适用于具有静态构造函数的类型.具有初始化表达式但没有静态构造函数的静态变量的类型可能会在类型初始化程序执行的时间方面表现出细微差别 - 但它会仍然只发生过一次.)

示范:

using System;

public sealed class Bang
{
    static Bang()
    {
        Console.WriteLine("In static constructor");
        throw new Exception("Bang!");
    }

    public static void Foo() {}
}

class Test
{
    static void Main()
    {
        for (int i = 0; i < 5; i++)
        {
            try
            {
                Bang.Foo();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.GetType().Name);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

In static constructor
TypeInitializationException
TypeInitializationException
TypeInitializationException
TypeInitializationException
TypeInitializationException
Run Code Online (Sandbox Code Playgroud)

如您所见,静态构造函数只被调用一次.

  • @James B:不,它在TypeInitializerException的InnerException中. (8认同)
  • 根据http://msdn.microsoft.com/en-us/library/bb386039.aspx ...它声明:`从静态构造函数中抛出异常会导致该类型在当前应用程序域中不可用.从静态构造函数中抛出异常应该有一个很好的理由(例如安全问题) (8认同)
  • 有趣的是,当你明确地抛出`Exception`时,你只捕获`TypeInitializationExceptions` ...那个'Exception`被吞下了吗? (6认同)
  • @James:不,你不应该在任何地方捕获TypeInitializationException.只有当一个类型被*致命*破坏时才会发生这种情况. (5认同)
  • 我认为这样做的一点是不要在静态构造函数中抛出异常,不要在任何地方捕获`TypeInitialisationException`,而不是乱用测试AppDomains.如果你必须开始跳过这些奇怪的箍,你几乎肯定会错过一些东西.詹姆斯班级的设计显然需要改变. (3认同)

Chr*_*ens 24

另外两个答案是你的直接问题的好答案 - 这是一个metaanswer - 当你检测到配置元素没有被填充时,你应该在方法中抛出异常,而不是在构造函数中.恕我直言,"未配置"是构造函数阶段中这些元素的有效配置状态,而不是在SendMail时间.这将回避整个问题.