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

时间:2013-03-06 14:33:56

标签: c# asp.net static constructor

首先,我在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可以在不声明静态构造函数的情况下实现相同的目的。 它的用途与初始化只有一次相同。

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

8 个答案:

答案 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检查