首先,我在What is the use of static constructors?得到了答案,但我想在这方面给出答案。
这是我的C#静态类:
public static class BasicClass
{
static int i = 0;
static BasicClass()
{
i = 10;
}
public static void Temp()
{
//some code
}
public static void Temp1()
{
//some code
}
}
在这里面我有一个静态变量i
,它在第一次调用时被初始化为10。所以基本上它可能是静态构造函数的目的,但是通过初始化static int i = 10
可以在不声明静态构造函数的情况下实现相同的目的。
它的用途与初始化只有一次相同。
那为什么我们需要一个静态构造函数?或者我在理解静态构造函数的概念或使用方面完全错误了吗?
答案 0 :(得分:23)
如果将该类编译成程序集,然后使用ILSpy或类似程序来反汇编结果,您会注意到所有静态成员初始化都是在静态构造函数中执行的。
例如,以下C#代码:
public static class BasicClass
{
static int i = 10;
}
将产生相当于IL的IL:
public static class BasicClass
{
static int i;
static BasicClass()
{
i = 10;
}
}
换句话说,直接初始化只是C#编译器提供的语法糖。在幕后,仍然实现了静态构造函数。
答案 1 :(得分:6)
嗯,在你的示例中,确实不需要它,但想象一下,当必须从数据库,文本文件或任何其他资源中读取i
值时?您可能需要以下内容:
static BasicClass()
{
using (SomeConnection con = Provider.OpenConnection())
{
try
{
// Some code here
}
catch
{
// Handling expeptions, setting default value
i = 10;
}
}
}
现在无法声明和初始化静态字段,使用静态构造函数可以提供更好的服务
答案 2 :(得分:1)
在这种情况下,您不需要静态构造函数。
static BasicClass()
{
i = 10;
}
和
static int i = 10;
在功能上是相同的。
答案 3 :(得分:1)
答案也在您的链接问题中:
[...]特别适用于将所需的配置数据读入只读字段等。
它在第一次运行时由运行时自动运行(那里的确切规则是复杂的(参见“beforefieldinit”),并在CLR2和CLR4之间巧妙地改变)。 >除非您滥用反射,否则保证最多运行一次(即使两个线程>同时到达)。
您可以在静态构造函数中初始化更复杂的东西,比如设置数据库连接等等。如果它有意义是另一回事......
答案 4 :(得分:1)
如果您需要在构造函数中执行某些操作,并且您希望应用程序中有一个唯一的实例,那么静态构造函数就有意义。例如:
public static class BasicClass
{
static MyConfiguration _myConfig;
static BasicClass()
{
// read configuration from file
_myConfig = ReadConfigFromConfigFile("somefile.conf");
}
private static MyConfiguration ReadConfigFromConfigFile(string file)
{
using (StreamReader reader = new StreamReader(file);
{
...
}
}
}
在您解释的场景中,您不需要显式的静态构造函数。
此外,您可以应用singleton pattern来实现此目的。
答案 5 :(得分:0)
您只能使用编译时常量(您的情况)初始化字段。但是在静态构造函数中,您可以执行一些代码(例如,读取配置文件)。
答案 6 :(得分:0)
静态构造函数不仅用于初始化变量的目的,还创建了(静态)类(或环境)在这些对象或类本身上工作和调用方法所必需的对象。 p>
答案 7 :(得分:0)
尚未提及的一个因素是,使用静态构造函数(使用构造函数语法编写)调用foo()
与使用静态字段初始化程序执行此操作之间存在语义差异。特别是,如果一个类型具有使用构造函数语法编写的静态构造函数,则保证在第一次“使用”该类型执行的代码时调用该构造函数;它之前不会被调用,如果不使用该类型也不会被调用。相比之下,虽然.NET保证类型的静态字段初始化程序在其任何静态字段被访问之前运行,并且不会运行多次,但.NET可以在第一次认为类型可能会使用。考虑例如:
if (someCondition())
for (i=0; i<100000000; i++)
someClass.someStaticField++;
如果Just-In-Time编译器遇到上述代码,someClass
从未使用过,并且它有一个使用静态构造函数语法声明的构造函数,则生成的机器代码将类似于:
if (someCondition())
for (i=0; i<100000000; i++)
{
if (someClass.hasBeenInitialized)
someClass.runConstructor();
someClass.someStaticField++;
}
在循环中执行if-check 。相比之下,如果有字段初始化但没有构造函数样式声明,JIT可能会在运行代码之前执行someClass
的静态构造,因此无需在其中包含if
检查