C# 静态构造函数中的异常

C# 静态构造函数中的异常,c#,exception,constructor,static-classes,C#,Exception,Constructor,Static Classes,我一直在寻找这个问题的答案,到目前为止,我能找到的最好的答案是,这是面向具有静态构造函数的实例的;我只是静态地使用这个类 我的代码: public static class MailHelper { private static string mailHost; static MailHelper() { var mailSettings = ConfigurationManager.GetSection("MailSettings") as NameVal

我一直在寻找这个问题的答案,到目前为止,我能找到的最好的答案是,这是面向具有静态构造函数的实例的;我只是静态地使用这个类

我的代码:

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样式。谢谢。

一旦类型初始值设定项失败一次,就不会重试。该类型在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);
            }
        }
    }
}
如您所见,静态构造函数只调用一次。

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

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


另外两个答案很好地回答了您的直接问题-这是一个元答案-当您检测到配置元素未填充时,应该在方法中抛出异常,而不是在构造函数中。IMHO,“未配置”是这些元素在构造函数阶段的有效配置状态,而不是在发送邮件时。这将回避整个问题。

它应该会失败,但是自己试一试又有什么错呢?我认为从(静态)构造函数中抛出是没有意义的,因为这样类就处于不稳定状态(未完全初始化)。如何创建一个显式的
Init()
函数,在使用之前调用它(如果已经初始化,它应该不会做任何事情),如果它抛出异常,不要使用classPontus>我想Jon可能还需要一些要点:)Cameron>我从来都不是Init()方法的忠实粉丝。。。如果使类可用需要Init(),为什么不在构造函数中执行呢?否则,您将把对象的控制权传递给调用方,您仍然需要测试被调用方法的有效性,因为您不能相信调用方做了他应该做的事情。我喜欢下面Chris的回答,这听起来像是你和我之间的妥协。。。在构造函数中设置配置,但不要抛出异常,而是检查静态方法中的设置。感谢PS。终于学会了缩进样式的名称!有趣的是,当您显式抛出
异常时,只捕获
类型初始化异常
。。。那个异常被吞没了吗?@James B:不,它在TypeInitializerException的InnerException中。@James:不,你不应该在任何地方捕获TypeInitializationException。基本上,只有当类型被致命破坏时才会发生这种情况。我认为这样做的好处是不要从静态构造函数中抛出异常,不要到处捕捉
TypeInitialisationException
,也不要乱弄测试应用域。如果你不得不开始跳过这些怪圈,你几乎肯定错过了什么。詹姆斯的课程设计显然需要改变。。。它声明:
从静态构造函数引发异常会导致该类型在当前应用程序域中不可用。对于从静态构造函数引发异常,您应该有一个很好的理由(例如安全问题)。
Jon实际上最正确地回答了我的问题,但是这个答案提出了一个比我的更好的解决方案。
In static constructor
TypeInitializationException
TypeInitializationException
TypeInitializationException
TypeInitializationException
TypeInitializationException