为什么这个静态构造函数没有被调用?

时间:2011-09-13 10:34:43

标签: c# asp.net web-services

我正在创建asp.net Web服务。我有一个类,当我尝试初始化该类的对象时,其静态构造函数未被调用。我无法理解这种行为。在静态构造函数中,我正在从web.config文件中读取值。

以下是代码的一部分:

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
    AppController extractor;

    public Service()
    {
        try
        {
            extractor = new AppController();
        }
        catch(Exception ex)
        {
            // I am not getting exception at this point.
        }
    }
}

public class AppController
{
    static string converterBatchFilePath = null;
    static string personalProfileOutputFolderPath = null;

    static AppController()
    {
        // reading some settings from web.config file
        try
        {
            converterBatchFilePath = ConfigurationManager.AppSettings["WordToTextConverterBatFilePath"];
        }
        catch(Exception ex)
        { // }
    }
    public AppController()
    {
        // do some initialization
    }
}

在调试Web服务时,我注意到只有实例构造函数被调用,控件永远不会转到静态构造函数。

任何人都知道为什么会这样吗?

我正在使用VS 2008 Express版和C#。

  

修改

实际上这个AppController是基于控制台的项目。我已将该项目添加为Web服务项目中的参考,然后使用它。如果我从命令行使用AppController,它工作正常,但它不能在Web服务项目内部工作。

6 个答案:

答案 0 :(得分:19)

我的猜测是,在你预期它被调用之前它被调用了。如果您已经调试过您的站点但没有回收AppPool,则很可能已经运行了静态构造函数。 类似地,任何访问任何静态成员的东西也会调用静态构造函数(如果尚未调用它)。

答案 1 :(得分:13)

今天我的静态初始化程序没有被调用。事实证明,在访问类的const成员之前,静态初始化程序是而不是

因为const值在编译时是已知的,所以这是有意义的,但它意味着the documentation表示"它在...之前被自动调用...任何静态成员被引用"在技​​术上是不正确的,至少与@JonSkeet's assertion结合使用"所有常量声明都是隐式静态"。

该程序演示了这个问题:

using System;

static class Program
{
    public static void Main()
    {
        Console.WriteLine("Constant={0}", Problem.Constant);
        Console.WriteLine("ReadOnly={0}", Problem.ReadOnly);
        Console.WriteLine("Field={0}", Problem.Field);
        Console.WriteLine("Property={0}", Problem.Property);
    }

    private static class Problem
    {
        public const int Constant = 1;
        public static readonly int ReadOnly = 2;
        public static int Field = 3;
        private static int mProperty = 4;
        public static int Property { get { return mProperty; } }

        static Problem()
        {
            Console.WriteLine("Problem: static initializer");
        }
    }
}

输出结果为:

常数= 1
问题:静态初始化器
只读= 2
字段= 3
属性= 4

(针对.NET 4.5进行测试。)

答案 2 :(得分:5)

静态构造函数用于初始化任何静态数据,或执行仅需执行一次的特定操作。在创建第一个实例或引用任何静态成员之前会自动调用它。

请注意 在创建第一个实例或引用任何静态成员之前,会自动调用静态构造函数来初始化类。和用户无法控制何时在程序中执行静态构造函数。

取自MSDN's Static Constructors (C# Programming Guide)

答案 3 :(得分:2)

我怀疑你的问题是由静态构造函数中引发的异常引起的,并且被创建实例的代码吞没了。

在静态字段初始化程序中,甚至可能更难以调试。

或许打破第一次机会异常有助于调试问题。


我根本不会将从配置文件中读取的代码放入静态构造函数中。我会将所有与配置相关的内容封装在一个类中,并将该类的实例传递给构造函数,可能使用的是IoC容器。

这有许多优点:

  • 您可以在同一个AppDomain中同时使用不同的配置
  • 您可以使用其他方式加载配置
  • 您不需要在静态构造函数中执行可能失败的复杂内容。正如您所看到的那样,静态构造函数往往会对调试产生问题,所以我只做简单的初始化而不依赖于外部状态

(我知道这不是一个答案,但评论的时间太长了)

答案 4 :(得分:1)

这是一个快速示例,我将它放在一起,从静态和实例构造函数中的提取器类中的配置文件中获取值。这对我有用 - 将它与你正在做的事情进行比较,看看有什么不同:

public class Service : System.Web.Services.WebService
{
    AppController extractor;

    [WebMethod]
    public string HelloWorld()
    {
        extractor = new AppController();
        return AppController.staticString + " :: " + extractor.instanceString;
    }
}

class AppController
{
    public static string staticString;
    public string instanceString;

    static AppController()
    {
        staticString = System.Configuration.ConfigurationManager.AppSettings["static"];
    }
    public AppController()
    {
        instanceString = System.Configuration.ConfigurationManager.AppSettings["instance"];
    }
}

我的web.config:

  <appSettings>
    <add key="static" value="blah blah"/>
    <add key="instance" value="ha ha"/>
  </appSettings>

我的回答:

<?xml version="1.0" encoding="UTF-8"?>
<string xmlns="http://tempuri.org/">blah blah :: ha ha</string>

答案 5 :(得分:0)

当我尝试通过在引用静态字段的行上放置一个断点进行调试时,我没有在静态构造函数上获得调试控制。

我将断点保留在静态构造函数入口处,从静态字段引用的行中删除了断点。现在,调试控件开始进入静态构造函数代码。

This image shows how your editor with breakpoints would look like