请给我解释一下静态构造函数的用法。为什么,什么时候我们要创建一个静态构造函数,它是否可能重载一个?


当前回答

不,你不能让它过载;静态构造函数对于初始化与类型相关的任何静态字段(或任何其他每种类型的操作)非常有用——特别是对于将所需的配置数据读入只读字段等非常有用。

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

其他回答

来自微软文档 https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors

静态构造函数(c#编程指南)

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

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;
    }
}

讲话

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

A static constructor doesn't take access modifiers or have parameters. A class or struct can only have one static constructor. Static constructors cannot be inherited or overloaded. 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. It initializes the class before the first instance is created or any static members declared in that class (not its base classes) are referenced. A static constructor runs 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're executed in the textual order in which they appear in the class declaration. The initializers run immediately prior to the execution of the static constructor. 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 doesn't invoke it a second time, and the type will remain uninitialized for the lifetime of the application domain. Most commonly, a xref:System.TypeInitializationException exception is thrown when a static constructor is unable to instantiate a type or for an unhandled exception occurring within a static constructor. For static constructors that aren't explicitly defined in source code, troubleshooting may require inspection of the intermediate language (IL) code. The presence of a static constructor prevents the addition of the xref:System.Reflection.TypeAttributes.BeforeFieldInit type attribute. This limits runtime optimization. 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 isn't required, initialize static fields at declaration rather than through a static constructor for better runtime optimization. The runtime calls a static constructor no more than once in a single application domain. That call is made in a locked region based on the specific type of the class. No additional locking mechanisms are needed in the body of a static constructor. To avoid the risk of deadlocks, don't block the current thread in static constructors and initializers. For example, don't wait on tasks, threads, wait handles or events, don't acquire locks, and don't execute blocking parallel operations such as parallel loops, Parallel.Invoke and Parallel LINQ queries.

[!请注意) 虽然不能直接访问,但应该记录显式静态构造函数的存在,以帮助排除初始化异常。

使用

静态构造函数的典型用法是类使用日志文件,构造函数用于向该文件写入条目。 当构造函数可以调用LoadLibrary方法时,静态构造函数在为非托管代码创建包装器类时也很有用。 静态构造函数也是一个方便的地方,可以强制执行在编译时不能通过类型参数约束进行检查的类型参数的运行时检查。

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

不,你不能让它过载;静态构造函数对于初始化与类型相关的任何静态字段(或任何其他每种类型的操作)非常有用——特别是对于将所需的配置数据读入只读字段等非常有用。

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

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

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

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

与常规枚举相比,它的优点是可以轻松封装相关信息。一个缺点是不能在switch语句中使用这些值(因为它需要常量值)。

静态构造函数只调用创建的类的第一个实例。并用于执行在类的生命周期中只需要执行一次的特定操作。