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

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

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

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

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

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

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

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

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

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

  • 如果不提供静态构造函数来初始化静态字段,则所有静态字段都将初始化为它们的默认值,如C#类型的默认值中所列。

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

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

  • 声明为静态只读的字段只能作为声明的一部分或在静态构造函数中分配。当不需要显式的静态构造函数时,请在声明时初始化静态字段,而不是通过静态构造函数进行初始化,以实现更好的运行时优化。

示例

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("静态构造函数被调用");
      }
      public Car(){
         Console.WriteLine("调用了默认构造函数");
      }
   }
}

输出结果

静态构造函数被调用
调用了默认构造函数
调用了默认构造函数

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

示例

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($"调用了静态构造函数。 全局开始时间:
         {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();
      }
   }
}

输出结果

调用了静态构造函数。 全局开始时间:
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.