为什么这个静态构造函数没有被调用
本文关键字:调用 构造函数 静态 为什么 | 更新日期: 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>
当我试图通过在静态字段引用的行上放置一个断点进行调试时,我没有得到对静态构造函数的调试控制。
我在静态构造函数入口保留了断点,从静态字段引用的行中删除了断点。现在调试控制开始进入静态构造函数代码。
这个图片显示了带有断点的编辑器的样子