9

首先,我在静态构造函数的用途是什么中得到了答案?,但我想在这种情况下得到答案。

这是我的 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 相同的目的,即只初始化一次。

那为什么我们需要一个静态构造函数呢?或者我在理解静态构造函数的概念或使用方面完全错误?

4

8 回答 8

23

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

例如,以下 C# 代码:

public static class BasicClass
{
    static int i = 10;
}

将产生相当于以下内容的 IL:

public static class BasicClass
{
    static int i;

    static BasicClass()
    {
        i = 10;
    }
}

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

于 2013-03-06T14:38:39.330 回答
6

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

static BasicClass()
{
    using (SomeConnection con = Provider.OpenConnection())
    {
        try
        {
            // Some code here
        }
        catch
        {
            // Handling expeptions, setting default value
            i = 10;
        }
    }
}

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

于 2013-03-06T14:38:52.213 回答
1

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

static BasicClass()
{
    i = 10;
}

static int i = 10;

功能相同。

于 2013-03-06T14:38:28.583 回答
1

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

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

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

您可以在静态构造函数中初始化更复杂的东西,例如建立数据库连接等。如果它有意义是另一回事......

于 2013-03-06T14:39:19.097 回答
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);
       {
         ...
       }
    }
}

在您解释的场景中,您不需要显式的静态构造函数。

此外,您可以应用单例模式来实现此目的。

于 2013-03-06T14:39:59.173 回答
0

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

于 2013-03-06T14:37:43.607 回答
0

静态构造函数不仅用于初始化变量的目的,而且还创建对象,这些对象可能是您的(静态)类(或环境)在这些对象或您的类本身上工作和调用方法所必需的。

于 2013-03-06T14:39:00.700 回答
0

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

if (someCondition())
  for (i=0; i<100000000; i++)
    someClass.someStaticField++;

如果当即时编译器遇到上述代码时,someClass从未使用过,并且它有一个使用静态构造函数语法声明的构造函数,则生成的机器代码将类似于:

if (someCondition())
  for (i=0; i<100000000; i++)
  {
    if (someClass.hasBeenInitialized)
      someClass.runConstructor();
    someClass.someStaticField++;
  }

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

于 2013-10-28T22:53:46.177 回答