C# 为什么我们需要静态构造函数?

C# 为什么我们需要静态构造函数?,c#,asp.net,static,constructor,C#,Asp.net,Static,Constructor,首先,我得到了一个答案,但我想在这方面得到一个答案 这是我的C#静态类: public static class BasicClass { static int i = 0; static BasicClass() { i = 10; } public static void Temp() { //some code } public static void Temp1() {

首先,我得到了一个答案,但我想在这方面得到一个答案

这是我的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
其用途与仅初始化一次的相同


那为什么我们需要一个静态构造函数呢?还是我完全错误地理解了静态构造函数的概念或用法?

您只能使用编译时常量就地初始化字段(您的情况)。但是在静态构造函数中,您可以执行一些代码(例如读取配置文件)。

在这种情况下,您不需要静态构造函数

static BasicClass()
{
    i = 10;
}


功能相同。

如果将该类编译成程序集,然后使用ILSpy或类似工具来反汇编结果,则会注意到所有静态成员初始化都是在静态构造函数中执行的

例如,以下C#代码:

将产生相当于:

public static class BasicClass
{
    static int i;

    static BasicClass()
    {
        i = 10;
    }
}

换句话说,直接初始化只是C#编译器提供的语法糖分。在引擎盖下,仍然实现了静态构造函数。

好吧,在您的示例中,它确实不需要,但是想象一下,当必须从数据库、文本文件或任何其他资源读取
i
值时?您可能需要以下内容:

static BasicClass()
{
    using (SomeConnection con = Provider.OpenConnection())
    {
        try
        {
            // Some code here
        }
        catch
        {
            // Handling expeptions, setting default value
            i = 10;
        }
    }
}
if (someCondition())
  for (i=0; i<100000000; i++)
  {
    if (someClass.hasBeenInitialized)
      someClass.runConstructor();
    someClass.someStaticField++;
  }

现在不可能声明和初始化静态字段,最好使用静态构造函数

静态构造函数不仅可以初始化变量,还可以创建(静态)类(或环境)可能需要的对象在这些对象或类本身上使用和调用方法。

答案也在您的链接问题中:

[…]特别适用于将所需配置数据读入只读字段等

它在第一次需要时由运行时自动运行(那里的确切规则>非常复杂(请参见“beforefieldinit”),并且在CLR2和CLR4之间进行了微妙的更改)。>除非滥用反射,否则它保证最多运行一次(即使两个线程>同时到达)


您可以在静态构造函数中初始化更复杂的事情,比如设置数据库连接等等。如果它有意义是另一回事……

如果您需要在构造函数内部执行一些操作,并且希望在应用程序中有一个唯一的实例,那么静态构造函数就有意义。例如:

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);
       {
         ...
       }
    }
}
if (someCondition())
  for (i=0; i<100000000; i++)
    someClass.someStaticField++;
在您解释的场景中,您不需要明确地使用静态构造函数


另外,您可以应用来实现此目的。

一个尚未提及的因素是,使用静态构造函数(使用构造函数语法编写)调用
foo()
与使用静态字段初始值设定项调用
之间存在语义差异。特别是,如果一个类型有一个使用构造函数语法编写的静态构造函数,那么保证在第一次执行将“使用”该类型的代码时调用该构造函数;在此之前不会调用它,如果不使用该类型,也不会调用它。相比之下,尽管.NET保证类型的静态字段初始值设定项将在访问其任何静态字段之前运行,并且不会运行多次,.NET可以在认为可能使用某个类型时自由运行此类静态初始值设定项。例如,考虑:

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);
       {
         ...
       }
    }
}
if (someCondition())
  for (i=0; i<100000000; i++)
    someClass.someStaticField++;

在循环中执行if检查。相反,如果有字段初始化,但没有构造函数样式的声明,JIT可能会在运行代码之前执行
someClass
的静态构造,因此无需在其中包含
if
检查。

如果您的程序使用配置文件怎么办?您需要将配置存储在静态变量中,但必须首先从文件中读取这些变量,如果文件不存在(或者由于其他原因无法打开),则需要将这些配置设置为默认值。这就是静态构造函数的用途。在静态构造函数中执行此类操作是危险的。如果初始化引发了一个未捕获的异常,那么就没有简单的方法来捕获它,并且该类型永远无法加载到appdomain中。在这种情况下,如果C#支持静态成员初始化(实际上会编译成静态构造函数),而不是实际的静态构造函数,这难道还不够吗?@svick,这可能适得其反。有时,您确实需要为类全局执行比成员初始化(例如简单循环和分支)更简单的操作。为什么要删除对CLR中可用且只要求静态构造函数从不抛出的功能的支持?