静态构造函数有什么用?

发布于 2024-10-08 21:15:21 字数 53 浏览 8 评论 0原文

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

Please explain to me the use of static constructor. Why and when would we create a static constructor and is it possible to overload one?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

优雅的叶子 2024-10-15 21:15:21

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

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

No you can't overload it; a static constructor is useful for initializing any static fields associated with a type (or any other per-type operations) - useful in particular for reading required configuration data into readonly fields, etc.

It is run automatically by the runtime the first time it is needed (the exact rules there are complicated (see "beforefieldinit"), and changed subtly between CLR2 and CLR4). Unless you abuse reflection, it is guaranteed to run at most once (even if two threads arrive at the same time).

望喜 2024-10-15 21:15:21

来自 静态构造函数(C# 编程指南)

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

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

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

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

  • 静态构造函数不能直接调用。

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

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

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

From Static Constructors (C# Programming Guide):

A static constructor is used to
initialize any static data, or to
perform a particular action that needs
performed once only. It is called
automatically before the first
instance is created or any static
members are referenced.

Static constructors have the following
properties:

  • A static constructor does not take access modifiers or have parameters.

  • 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 cannot be called directly.

  • The user has no control on when the static constructor is executed in the program.

  • 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.

  • Static constructors are also useful when creating wrapper classes for unmanaged code, when the constructor can call the LoadLibrary method.

悸初 2024-10-15 21:15:21

当您的静态字段相互依赖且初始化顺序很重要时,静态构造函数也非常有用。如果您通过更改字段顺序的格式化程序/美化器运行代码,那么您可能会发现自己出现了意想不到的空值。

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

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

当您访问 fullUr 时,它将是“http://www.fullUr”。 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/”,因为设置 fullUrl 时,urlFragment 尚未初始化。不好。因此,您添加一个静态构造函数来处理初始化:

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

    static ScopeMonitor()
    {
        fullUrl= firstPart + urlFragment;

    }
}

现在,无论字段的顺序如何,初始化始终都是正确的。

Static constructors are also very useful when you have static fields that rely upon each other such that the order of initialization is important. If you run your code through a formatter/beautifier that changes the order of the fields then you may find yourself with null values where you didn't expect them.

Example: Suppose we had this class:

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

When you access fullUr, it will be "http://www.example.com/foo/bar".

Months later you're cleaning up your code and alphabetize the fields (let's say they're part of a much larger list, so you don't notice the problem). You have:

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

Your fullUrl value is now just "http://www.example.com/" since urlFragment hadn't been initialized at the time fullUrl was being set. Not good. So, you add a static constructor to take care of the initialization:

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

    static ScopeMonitor()
    {
        fullUrl= firstPart + urlFragment;

    }
}

Now, no matter what order you have the fields, the initialization will always be correct.

手心的海 2024-10-15 21:15:21

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

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

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

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

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

4.它不应该有访问修饰符。

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

1.It can only access the static member(s) of the class.

Reason : Non static member is specific to the object instance. If static constructor are allowed to work on non static members it will reflect the changes in all the object instance, which is impractical.

2.There should be no parameter(s) in static constructor.

Reason: Since, It is going to be called by CLR, nobody can pass the parameter to it.
3.Only one static constructor is allowed.

Reason: Overloading needs the two methods to be different in terms of method/constructor definition which is not possible in static constructor.

4.There should be no access modifier to it.

Reason: Again the reason is same call to static constructor is made by CLR and not by the object, no need to have access modifier to it

赠意 2024-10-15 21:15:21

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

you can use static constructor to initializes static fields. It runs at an indeterminate time before those fields are used. Microsoft's documentation and many developers warn that static constructors on a type impose a substantial overhead.
It is best to avoid static constructors for maximum performance.
update: you can't use more than one static constructor in the same class, however you can use other instance constructors with (maximum) one static constructor.

计㈡愣 2024-10-15 21:15:21

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

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

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相比,它的优点是您可以轻松封装相关信息。一个缺点是您不能在 switch 语句中使用这些值(因为它需要常量值)。

Why and when would we create a static constructor ...?

One specific reason to use a static constructor is to create a 'super enum' class. Here's a (simple, contrived) example:

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

You'd use it very similarly (in syntactical appearance) to any other enum:

Animals.Dog

The advantage of this over a regular enum is that you can encapsulate related info easily. One disadvantage is that you can't use these values in a switch statement (because it requires constant values).

一身仙ぐ女味 2024-10-15 21:15:21

来自微软文档
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors" 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;
    }
}

备注

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

  • 静态构造函数不采用访问修饰符,也不具有参数。
  • 一个类或结构只能有一个静态构造函数。
  • 静态构造函数不能被继承或重载。
  • 静态构造函数不能直接调用,只能由公共语言运行时 (CLR) 调用。它是自动调用的。
  • 用户无法控制静态构造函数何时在程序中执行。
  • 自动调用静态构造函数。它在创建第一个实例或引用该类(不是其基类)中声明的任何静态成员之前初始化该类。静态构造函数在实例构造函数之前运行。当调用分配给事件或委托的静态方法时(而不是分配它时)将调用类型的静态构造函数。如果静态构造函数的类中存在静态字段变量初始值设定项,则它们按照它们在类声明中出现的文本顺序执行。初始化程序在静态构造函数执行之前立即运行。
  • 如果不提供静态构造函数来初始化静态字段,则所有静态字段都将初始化为 C# 类型的默认值中列出的默认值。
  • 如果静态构造函数引发异常,运行时不会再次调用它,并且该类型将在应用程序域的生命周期内保持未初始化状态。最常见的是,当静态构造函数无法实例化类型或静态构造函数内发生未处理的异常时,会引发 System.TypeInitializationException 异常。对于源代码中未显式定义的静态构造函数,故障排除可能需要检查中间语言 (IL) 代码。
  • 静态构造函数的存在会阻止添加 System.Reflection.TypeAttributes.BeforeFieldInit 类型属性。这限制了运行时优化。
  • 声明为static readonly 的字段只能作为其声明的一部分或在静态构造函数中进行分配。当不需要显式静态构造函数时,请在声明时初始化静态字段,而不是通过静态构造函数来初始化,以获得更好的运行时优化。
  • 运行时在单个应用程序域中调用静态构造函数不超过一次。该调用是根据类的特定类型在锁定区域中进行的。静态构造函数的主体中不需要额外的锁定机制。为了避免死锁的风险,不要在静态构造函数和初始值设定项中阻止当前线程。例如,不要等待任务、线程、等待句柄或事件,不要获取锁,也不要执行阻塞并行操作,例如并行循环、Parallel.Invoke 和并行 LINQ 查询。

[!注意]
尽管无法直接访问,但应记录显式静态构造函数的存在,以帮助排除初始化异常。

用法

  • 静态构造函数的典型用途是当类使用日志文件并且构造函数用于将条目写入该文件时。
  • 当构造函数可以调用 LoadLibrary 方法时,静态构造函数在为非托管代码创建包装类时也很有用。
  • 静态构造函数也是对类型参数强制执行运行时检查的便捷位置,而类型参数无法在编译时通过类型参数约束进行检查。

From Microsoft documentation
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors

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 only once. 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 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.

[!Note]
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.
  • 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 type-parameter constraints.
[浮城] 2024-10-15 21:15:21

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

Static constructor called only the first instance of the class created. and used to perform a particular action that needs to be performed only once in the life cycle of the class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文