C# 中的静态构造函数有什么用?

csharpserver side programmingprogramming更新于 2025/9/30 14:52:17

静态构造函数用于初始化任何静态数据,或执行只需执行一次的特定操作。它会在创建第一个实例或引用任何静态成员之前自动调用。

静态构造函数在为非托管代码创建包装类时非常有用,因为构造函数可以调用 LoadLibrary 方法。静态构造函数还可以方便地对无法在编译时通过约束检查的类型参数执行运行时检查。

静态构造函数具有以下属性 −

  • 静态构造函数不接受访问修饰符,也不包含参数。

  • 一个类或结构体只能有一个静态构造函数。

  • 静态构造函数不能被继承或重载。

  • 静态构造函数不能直接调用,只能由公共语言运行时 (CLR) 调用。它会被自动调用。

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

  • 在创建第一个实例或引用任何静态成员之前,会自动调用静态构造函数来初始化类。静态构造函数将在实例构造函数之前运行。类型的静态构造函数在调用分配给事件或委托的静态方法时调用,而不是在赋值时调用。如果静态字段变量初始化器存在于静态构造函数的类中,则它们将按照它们在类声明中出现的文本顺序执行,紧接着执行静态构造函数。

  • 如果您没有提供静态构造函数来初始化静态字段,则所有静态字段都将初始化为其默认值,如"C# 类型的默认值"中所述。

  • 如果静态构造函数抛出异常,运行时将不会再次调用它,并且该类型将在程序运行的应用程序域的整个生命周期内保持未初始化状态。最常见的情况是,当静态构造函数无法实例化类型或静态构造函数中发生未处理的异常时,会抛出 TypeInitializationException 异常。对于未在源代码中明确定义的隐式静态构造函数,故障排除可能需要检查中间语言 (IL) 代码。

  • 静态构造函数的存在会阻止添加 BeforeFieldInit 类型属性。这会限制运行时优化。

  • 声明为 static readonly 的字段只能在其声明过程中或在静态构造函数中赋值。当不需要显式静态构造函数时,请在声明时初始化静态字段,而不是通过静态构造函数初始化,以便更好地进行运行时优化。

示例

using System;
namespace DemoApplication{
   public class Program{
      static void Main(string[] args){
         Car user = new Car();
         Car user1 = new Car();
         Console.ReadLine();
      }
   }
   public class Car{
      static Car(){
         Console.WriteLine("Static constructor called");
      }
      public Car(){
         Console.WriteLine("Default constructor called");
      }
   }
}

输出

Static constructor called
Default constructor called
Default constructor called

在上面的例子中,我们可以看到静态构造函数只被调用一次。

示例

using System;
using System.Threading;
namespace DemoApplication{
   public class Car{
      protected static readonly DateTime globalStartTime;
      protected int RouteNumber { get; set; }
      static Car(){
         globalStartTime = DateTime.Now;
         Console.WriteLine($"Static constructor called. Global start time:
         {globalStartTime.ToLongTimeString()}");
      }
      public Car(int routeNum){
         RouteNumber = routeNum;
         Console.WriteLine($"Car {RouteNumber} is created.");
      }
      public void Drive(){
         TimeSpan elapsedTime = DateTime.Now - globalStartTime;
         Console.WriteLine($"Car {this.RouteNumber} is starting its route
         {elapsedTime.Milliseconds} minutes after global start time
         {globalStartTime.ToShortTimeString()}.");
      }
   }
   class TestCar{
      static void Main(){
         Car car1 = new Car(1);
         Car car2 = new Car(2);
         car1.Drive();
         Thread.Sleep(25);
         car2.Drive();
         Console.ReadLine();
      }
   }
}

输出

Static constructor called. Global start time:
7:09:06 AM
Car 1 is created.
Car 2 is created.
Car 1 is starting its route25 minutes after global start time7:09 AM.
Car 2 is starting its route50 minutes after global start time7:09 AM.

相关文章