43

我已经在 SO 周围寻找答案,到目前为止我能找到的最好的是here,但是它适用于具有静态构造函数的实例;我只是静态地使用这个类。

我的代码:

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);


.

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

PS:抱歉,如果您不喜欢 Stroustrup 版本的 K&R 牙套样式,但不要编辑我的帖子只是为了将牙套更改为您喜欢的 Allman 样式。谢谢。

4

3 回答 3

99

一旦一个类型初始化器失败了一次,它就永远不会重试。该类型在 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);
            }
        }
    }
}

输出:

In static constructor
TypeInitializationException
TypeInitializationException
TypeInitializationException
TypeInitializationException
TypeInitializationException

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

于 2011-01-19T16:31:49.530 回答
26

The other two answers are good answers to your direct question - here's a metaanswer - you should be throwing the exception in the method when you detect that the configuration elements are not populated, rather than in the constructor. IMHO, "not configured" is a valid configuration state for those elements at the constructor phase, just not at SendMail time. That will sidestep this whole problem.

于 2011-01-19T16:34:43.540 回答
19

来自Microsoft 文档(静态构造函数(C# 编程指南)):

如果静态构造函数抛出异常,运行时将不会再次调用它,并且该类型将在程序运行的应用程序域的生命周期内保持未初始化状态。最常见的情况是,当静态构造函数无法实例化类型或静态构造函数中发生未处理的异常时,会引发TypeInitializationException异常。对于未在源代码中明确定义的隐式静态构造函数,故障排除可能需要检查中间语言 (IL) 代码。

于 2011-01-19T16:32:39.957 回答