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

本文关键字:调用 构造函数 静态 为什么 | 更新日期: 2023-09-27 18:08:31

我正在创建asp.net web服务。我有一个类,当我试图初始化该类的对象时,它的静态构造函数没有被调用。我不能理解这种行为。在静态构造函数我从web读取值。配置文件。

下面是部分代码:

[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服务时,我注意到只有实例构造函数被调用,而控制从未转到静态构造函数。

有人知道为什么会这样吗?

我使用的是vs2008 Express版和c#。

编辑

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

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

今天我的静态初始化器没有被调用。在访问类的const成员之前,不能调用静态初始化器

由于const值在编译时是已知的,这是有意义的,但这意味着文档中声明"它在…之前自动调用"。从技术上讲,"任何静态成员都被引用"是不正确的,至少当@JonSkeet断言"所有常量声明都是隐式静态的"时是不正确的。

这个程序演示了这个问题:

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测试)

我的猜测是在您期望调用它之前调用了它。如果您已经调试了站点,但没有回收appool,那么很可能已经运行了静态构造函数。类似地,任何访问任何静态成员的东西也将调用静态构造函数,如果它尚未被调用的话。

我怀疑您的问题是由静态构造函数中引发的异常引起的,该异常被创建实例的代码所吞噬。

甚至可能在静态字段初始化器中出现异常,这更加难以调试。

也许在第一次出现异常时启用断点有助于调试问题。


我根本不会把从配置文件中读取的代码放入静态构造函数中。相反,我将封装所有的配置依赖的东西,你在一个类和传递该类的一个实例到你的构造函数,可能使用IoC容器。

这有很多优点:

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

(我知道这不是一个答案,但它太长了,不能评论)

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

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

摘自MSDN的静态构造函数(c#编程指南)

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

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>

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

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

这个图片显示了带有断点的编辑器的样子