静态构造函数(C# 编程指南)Static Constructors (C# Programming Guide)

静态构造函数用于初始化任何静态数据,或执行仅需执行一次的特定操作。A static constructor is used to initialize any static data, or to perform a particular action that needs to be performed once only. 将在创建第一个实例或引用任何静态成员之前自动调用静态构造函数。It is called automatically before the first instance is created or any static members are referenced.

class SimpleClass
{
    // Static variable that must be initialized at run time.
    static readonly long baseline;

    // Static constructor is called at most one time, before any
    // instance constructor is invoked or member is accessed.
    static SimpleClass()
    {
        baseline = DateTime.Now.Ticks;
    }
}

备注Remarks

静态构造函数具有以下属性:Static constructors have the following properties:

  • 静态构造函数不使用访问修饰符或不具有参数。A static constructor does not take access modifiers or have parameters.

  • 类或结构只能有一个静态构造函数。A class or struct can only have one static constructor.

  • 静态构造函数不能继承或重载。Static constructors cannot be inherited or overloaded.

  • 静态构造函数不能直接调用,并且仅应由公共语言运行时 (CLR) 调用。A static constructor cannot be called directly and is only meant to be called by the common language runtime (CLR). 可以自动调用它们。It is invoked automatically.

  • 用户无法控制在程序中执行静态构造函数的时间。The user has no control on when the static constructor is executed in the program.

  • 在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数以初始化A static constructor is called automatically to initialize the class before the first instance is created or any static members are referenced. 静态构造函数应在实例构造函数之前运行。A static constructor will run before an instance constructor. 调用(而不是分配)分配给事件或委托的静态方法时,将调用类型的静态构造函数。A type's static constructor is called when a static method assigned to an event or a delegate is invoked and not when it is assigned. 如果静态构造函数类中存在静态字段变量初始值设定项,它们将在执行静态构造函数之前立即以在类声明中显示的文本顺序执行。If static field variable initializers are present in the class of the static constructor, they will be executed in the textual order in which they appear in the class declaration immediately prior to the execution of the static constructor.

  • 如果未提供静态构造函数来初始化静态字段,会将所有静态字段初始化为其默认值,如 C# 类型的默认值中所列。If you don't provide a static constructor to initialize static fields, all static fields are initialized to their default value as listed in Default values of C# types.

  • 如果静态构造函数引发异常,运行时将不会再次调用该函数,并且类型在程序运行所在的应用程序域的生存期内将保持未初始化。If a static constructor throws an exception, the runtime will not invoke it a second time, and the type will remain uninitialized for the lifetime of the application domain in which your program is running. 大多数情况下,当静态构造函数无法实例化一个类型时,或者当静态构造函数中发生未经处理的异常时,将引发 TypeInitializationException 异常。Most commonly, a TypeInitializationException exception is thrown when a static constructor is unable to instantiate a type or for an unhandled exception occurring within a static constructor. 对于未在源代码中显式定义的隐式静态构造函数,故障排除可能需要检查中间语言 (IL) 代码。For implicit static constructors that are not explicitly defined in source code, troubleshooting may require inspection of the intermediate language (IL) code.

  • 静态构造函数的存在将防止添加 BeforeFieldInit 类型属性。The presence of a static constructor prevents the addition of the BeforeFieldInit type attribute. 这将限制运行时优化。This limits runtime optimization.

  • 声明为 static readonly 的字段可能仅被分配为其声明的一部分或在静态构造函数中。A field declared as static readonly may only be assigned as part of its declaration or in a static constructor. 如果不需要显式静态构造函数,请在声明时初始化静态字段,而不是通过静态构造函数实现更好的运行时优化。When an explicit static constructor is not required, initialize static fields at declaration, rather than through a static constructor for better runtime optimization.

备注

尽管不可直接访问,但应记录显式静态构造函数的存在,以帮助故障排除初始化异常。Though not directly accessible, the presence of an explicit static constructor should be documented to assist with troubleshooting initialization exceptions.

用法Usage

  • 静态构造函数的一种典型用法是在类使用日志文件且将构造函数用于将条目写入到此文件中时使用。A typical use of static constructors is when the class is using a log file and the constructor is used to write entries to this file.

  • 静态构造函数对于创建非托管代码的包装类也非常有用,这种情况下构造函数可调用 LoadLibrary 方法。Static constructors are also useful when creating wrapper classes for unmanaged code, when the constructor can call the LoadLibrary method.

  • 也可在静态构造函数中轻松地对无法在编译时通过约束(类型参数约束)检查的类型参数强制执行运行时检查。Static constructors are also a convenient place to enforce run-time checks on the type parameter that cannot be checked at compile time via constraints (Type parameter constraints).

示例Example

在此示例中,类 Bus 具有静态构造函数。In this example, class Bus has a static constructor. 创建 Bus 的第一个实例 (bus1) 时,将调用该静态构造函数,以便初始化类。When the first instance of Bus is created (bus1), the static constructor is invoked to initialize the class. 示例输出验证即使创建了两个 Bus 的实例,静态构造函数也仅运行一次,并且在实例构造函数运行前运行。The sample output verifies that the static constructor runs only one time, even though two instances of Bus are created, and that it runs before the instance constructor runs.

 public class Bus
 {
     // Static variable used by all Bus instances.
     // Represents the time the first bus of the day starts its route.
     protected static readonly DateTime globalStartTime;

     // Property for the number of each bus.
     protected int RouteNumber { get; set; }

     // Static constructor to initialize the static variable.
     // It is invoked before the first instance constructor is run.
     static Bus()
     {
         globalStartTime = DateTime.Now;

         // The following statement produces the first line of output,
         // and the line occurs only once.
         Console.WriteLine("Static constructor sets global start time to {0}",
             globalStartTime.ToLongTimeString());
     }

     // Instance constructor.
     public Bus(int routeNum)
     {
         RouteNumber = routeNum;
         Console.WriteLine("Bus #{0} is created.", RouteNumber);
     }

     // Instance method.
     public void Drive()
     {
         TimeSpan elapsedTime = DateTime.Now - globalStartTime;

         // For demonstration purposes we treat milliseconds as minutes to simulate
         // actual bus times. Do not do this in your actual bus schedule program!
         Console.WriteLine("{0} is starting its route {1:N2} minutes after global start time {2}.",
                                 this.RouteNumber,
                                 elapsedTime.Milliseconds,
                                 globalStartTime.ToShortTimeString());
     }
 }

 class TestBus
 {
     static void Main()
     {
         // The creation of this instance activates the static constructor.
         Bus bus1 = new Bus(71);

         // Create a second bus.
         Bus bus2 = new Bus(72);

         // Send bus1 on its way.
         bus1.Drive();

         // Wait for bus2 to warm up.
         System.Threading.Thread.Sleep(25);

         // Send bus2 on its way.
         bus2.Drive();

         // Keep the console window open in debug mode.
         System.Console.WriteLine("Press any key to exit.");
         System.Console.ReadKey();
     }
 }
 /* Sample output:
     Static constructor sets global start time to 3:57:08 PM.
     Bus #71 is created.
     Bus #72 is created.
     71 is starting its route 6.00 minutes after global start time 3:57 PM.
     72 is starting its route 31.00 minutes after global start time 3:57 PM.
*/

C# 语言规范C# language specification

有关详细信息,请参阅 C# 语言规范中的静态构造函数部分。For more information, see the Static constructors section of the C# language specification.

请参阅See also