静态构造函数有什么用?

时间:2010-12-22 07:20:15

标签: c# constructor static-constructor

请向我解释一下静态构造函数的用法。我们为什么以及何时创建静态构造函数,是否可以重载一个?

10 个答案:

答案 0 :(得分:234)

不,你不能超载它;静态构造函数可用于初始化与类型(或任何其他每类操作)关联的任何静态字段 - 特别适用于将所需的配置数据读入只读字段等。

它在第一次运行时由运行时自动运行(确切的规则很复杂(参见“beforefieldinit”),并在CLR2和CLR4之间巧妙地改变)。除非您滥用反射,否则保证最多运行一次(即使两个线程同时到达)。

答案 1 :(得分:108)

来自Static Constructors (C# Programming Guide)

  

使用静态构造函数   初始化任何静态数据,或者   执行需要的特定操作   仅执行一次。它被称为   自动在第一个之前   实例已创建或任何静态   成员被引用。

     

静态构造函数具有以下内容   属性:

     
      
  • 静态构造函数不接受访问修饰符或具有参数。

  •   
  • 在创建第一个实例或引用任何静态成员之前,会自动调用静态构造函数来初始化类。

  •   
  • 无法直接调用静态构造函数。

  •   
  • 用户无法控制程序中何时执行静态构造函数。

  •   
  • 静态构造函数的典型用法是当类使用日志文件并使用构造函数将条目写入此文件时。

  •   
  • 当构造函数可以调用LoadLibrary方法时,静态构造函数在为非托管代码创建包装类时也很有用。

  •   

答案 2 :(得分:87)

当您具有相互依赖的静态字段时,静态构造函数也非常有用,这样初始化顺序很重要。如果您通过更改字段顺序的格式化程序/美化程序运行代码,那么您可能会发现自己的值为空值,而您并不期望它们。

示例:假设我们有这个类:

class ScopeMonitor
{
    static string urlFragment = "foo/bar";
    static string firstPart= "http://www.example.com/";
    static string fullUrl= firstPart + urlFragment;
}

当您访问fullUr时,它将是“http://www.example.com/foo/bar”。

几个月后,您正在清理代码并按字母顺序排列字段(假设它们是更大列表的一部分,因此您不会注意到问题)。你有:

class ScopeMonitor
{
    static string firstPart= "http://www.example.com/";
    static string fullUrl= firstPart + urlFragment;
    static string urlFragment = "foo/bar";
}

您的fullUrl值现在只是“http://www.example.com/”,因为urlFragment在设置fullUrl时尚未初始化。不好。因此,您添加一个静态构造函数来处理初始化:

class ScopeMonitor
{
    static string firstPart= "http://www.example.com/";
    static string fullUrl;
    static string urlFragment = "foo/bar";

    static ScopeMonitor()
    {
        fullUrl= firstPart + urlFragment;

    }
}

现在,无论您拥有哪些字段,初始化始终都是正确的。

答案 3 :(得分:14)

1.它只能访问该类的静态成员。

原因:非静态成员特定于对象实例。如果允许静态构造函数在非静态成员上工作,它将反映所有对象实例中的更改,这是不切实际的。

2.静态构造函数中不应有任何参数。

原因:因为,它将由CLR调用,没有人可以将参数传递给它。 3.只允许一个静态构造函数。

原因:重载需要两个方法在方法/构造函数定义方面不同,这在静态构造函数中是不可能的。

4.应该没有访问修饰符。

原因:原因是同样的调用静态构造函数是由CLR而不是对象调用的,不需要有访问修饰符

答案 4 :(得分:9)

您可以使用静态构造函数初始化静态字段。它在使用这些字段之前的不确定时间运行。微软的文档和许多开发人员警告说,类型上的静态构造函数会产生很大的开销。
最好避免使用静态构造函数来获得最大性能。
更新:您不能在同一个类中使用多个静态构造函数,但是您可以将其他实例构造函数与(最多)一个静态构造函数一起使用。

答案 5 :(得分:5)

  

为什么以及何时创建静态构造函数......?

使用静态构造函数的一个特定原因是创建一个“超级枚举”类。这是一个(简单,人为)的例子:

> mtcars$hp[mtcars$hp >= 200] = "high"
> head(mtcars, 20)
                     mpg cyl  disp   hp drat    wt  qsec vs am gear carb newcol
Mazda RX4           21.0   6 160.0 high 3.90 2.620 16.46  0  1    4    4    low
Mazda RX4 Wag       21.0   6 160.0 high 3.90 2.875 17.02  0  1    4    4    low
Datsun 710          22.8   4 108.0 high 3.85 2.320 18.61  1  1    4    1   high
Hornet 4 Drive      21.4   6 258.0 high 3.08 3.215 19.44  1  0    3    1    low
Hornet Sportabout   18.7   8 360.0 high 3.15 3.440 17.02  0  0    3    2 medium
Valiant             18.1   6 225.0 high 2.76 3.460 20.22  1  0    3    1    low
Duster 360          14.3   8 360.0 high 3.21 3.570 15.84  0  0    3    4 medium
Merc 240D           24.4   4 146.7 high 3.69 3.190 20.00  1  0    4    2   high
Merc 230            22.8   4 140.8 high 3.92 3.150 22.90  1  0    4    2   high
Merc 280            19.2   6 167.6 high 3.92 3.440 18.30  1  0    4    4    low
Merc 280C           17.8   6 167.6 high 3.92 3.440 18.90  1  0    4    4    low
Merc 450SE          16.4   8 275.8 high 3.07 4.070 17.40  0  0    3    3 medium
Merc 450SL          17.3   8 275.8 high 3.07 3.730 17.60  0  0    3    3 medium
Merc 450SLC         15.2   8 275.8 high 3.07 3.780 18.00  0  0    3    3 medium
Cadillac Fleetwood  10.4   8 472.0 high 2.93 5.250 17.98  0  0    3    4 medium
Lincoln Continental 10.4   8 460.0 high 3.00 5.424 17.82  0  0    3    4 medium
Chrysler Imperial   14.7   8 440.0 high 3.23 5.345 17.42  0  0    3    4 medium
Fiat 128            32.4   4  78.7 high 4.08 2.200 19.47  1  1    4    1   high
Honda Civic         30.4   4  75.7 high 4.93 1.615 18.52  1  1    4    2   high
Toyota Corolla      33.9   4  71.1 high 4.22 1.835 19.90  1  1    4    1   high 

你使用它(在句法外观上)与任何其他枚举非常相似:

public class Animals
{
    private readonly string _description;
    private readonly string _speciesBinomialName;

    public string Description { get { return _description; } }
    public string SpeciesBinomialName { get { return _speciesBinomialName; } }

    private Animals(string description, string speciesBinomialName)
    {
        _description = description;
        _speciesBinomialName = speciesBinomialName;
    }

    private static readonly Animals _dog;
    private static readonly Animals _cat;
    private static readonly Animals _boaConstrictor;

    public static Animals Dog { get { return _dog; } }
    public static Animals Cat { get { return _cat; } }
    public static Animals BoaConstrictor { get { return _boaConstrictor; } }

    static Animals()
    {
        _dog = new Animals("Man's best friend", "Canis familiaris");
        _cat = new Animals("Small, typically furry, killer", "Felis catus");
        _boaConstrictor = new Animals("Large, heavy-bodied snake", "Boa constrictor");
    }
}

这比普通Animals.Dog 的优势在于您可以轻松地封装相关信息。一个缺点是您不能在enum语句中使用这些值(因为它需要常量值)。

答案 6 :(得分:2)

静态构造函数

使用static modifier声明的构造函数是一个静态构造函数。静态构造函数用于初始化静态数据或执行需要在类的生命周期中仅执行一次的特定操作。静态构造函数是在类中执行的第一个代码块。静态构造函数在类的生命周期中执行一次且仅执行一次。它会自动调用。静态构造函数不接受任何参数。它没有访问说明符。它不是直接调用的。

答案 7 :(得分:0)

Static constructor仅调用所创建类的第一个实例。并用于执行特定的动作,该动作在类的生命周期中只需执行一次。

答案 8 :(得分:-1)

  

静态构造函数用于尽快初始化静态数据成员   因为第一次引用类,而实例构造函数   用于使用关键字创建该类的实例。

来源:http://www.c-sharpcorner.com/article/static-constructor-in-C-Sharp-and-their-usages/

答案 9 :(得分:-3)

using System;
namespace Constructor
{
class Test
{
//Declaration and initialization of static data member 
private static int id = 5;
public static int Id
{
get
{
return id;
}
}
public static void print()
{
Console.WriteLine("Test.id = " + id);
}
static void Main(string[] args)
{
//Print the value of id 
Test.print();
}
}
}

In the above example, static data member <id> is declared and initialized in same line. So if you compile and run this program your output would look similar to this :

Test.id = 5

Lets create one more class similar to class Test but this time the value of its static data member would depend on the value of static data member <id> of class Test.id.

//File Name : Test1.cs
using System;
namespace Constructor
{
class Test1
{
private static int id ;
//Static constructor, value of data member id is set conditionally here. 
//This type of initialization is not possible at the time of declaration.
static Test1()
{
if( Test.Id < 10 )
{
id = 20;
}
else
{
id = 100; 
}
Console.WriteLine("Static<Class> Constructor for Class Test1 Called..");
}
public static void print()
{
Console.WriteLine("Test1.id = " + id);
}
static void Main(string[] args)
{
//Print the value of id 
Test1.print();
}
}
}

As you can see in the above static constructor, static data member <id> is initialized conditionally. This type of initialization is not possible at the time of declaration. This is where static constructor comes in picture