静态构造函数有什么用?

Dr.*_*len 290 c# constructor static-constructor

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

Mar*_*ell 249

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

它在第一次运行时由运行时自动运行(确切的规则很复杂(参见"beforefieldinit"),并在CLR2和CLR4之间巧妙地改变).除非您滥用反射,否则保证最多运行一次(即使两个线程同时到达).

  • @Rajesh - 找到方法并调用`Invoke`20次. (24认同)
  • 谢谢你的答复.你可以请你提供更多关于你的句子的详细信息"除非你滥用反射,否则保证最多运行一次"......关于静态构造函数的反思可以做些什么.. (3认同)
  • 对于任何对静态构造函数初始化如何从 CLR 2 更改为 CLR 4 感兴趣的人,请参阅 Jon Skeet 的博客文章 (https://codeblog.jonskeet.uk/2010/01/26/type-in​​itialization-changes-in-net-4-0/ ) 总结得很好:CLR 2 使用急切初始化,而 CLR 4 使用延迟初始化。 (3认同)
  • @Johnny_D 非常确定在 CLR4 中存在可以推迟的条件 - 确切的情况需要进行一些挖掘。重新线程安全:在理智的情况下,是的 - 基本上。如果你通过反思滥用它们:不是那么多 (2认同)

Adr*_*der 111

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

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

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

  • 静态构造函数不接受访问修饰符或具有参数.

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

  • 无法直接调用静态构造函数.

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

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

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


Mar*_*uer 92

当静态字段相互依赖时,静态构造函数也非常有用,这样初始化顺序很重要.如果您通过更改字段顺序的格式化程序/美化程序运行代码,那么您可能会发现自己的值为空值,而您并不期望它们.

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

class ScopeMonitor
{
    static string urlFragment = "foo/bar";
    static string firstPart= "http://www.example.com/";
    static string fullUrl= firstPart + urlFragment;
}
Run Code Online (Sandbox Code Playgroud)

访问时fullUr,它将是" http://www.example.com/foo/bar ".

几个月后,你正在清理你的代码并按字母顺序排列字段(假设它们是一个更大的列表的一部分,所以你没有注意到这个问题).你有:

class ScopeMonitor
{
    static string firstPart= "http://www.example.com/";
    static string fullUrl= firstPart + urlFragment;
    static string urlFragment = "foo/bar";
}
Run Code Online (Sandbox Code Playgroud)

您的fullUrl价值现在只是" http://www.example.com/ ",因为urlFragment当时尚未初始化fullUrl.不好.因此,您添加一个静态构造函数来处理初始化:

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

    static ScopeMonitor()
    {
        fullUrl= firstPart + urlFragment;

    }
}
Run Code Online (Sandbox Code Playgroud)

现在,无论您拥有哪些字段,初始化始终都是正确的.

  • 如果您使用的是ReSharper,那么我相信在初始化urlFragment之前尝试设置fullUrl时,它将在这种情况下警告您。尽管如此,还是很好的例子。 (2认同)
  • @NoChance重新阅读我的评论,我相信当我说带有初始化器的字段需要在静态构造函数之前时我说错了。无论它们位于文件中的哪个位置,它们都将在执行静态构造函数之前初始化。 (2认同)

rav*_*jag 14

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

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

2.静态构造函数中应该没有参数.

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

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

4.它应该没有访问修饰符.

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


Dot*_*cer 10

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


Ken*_*itt 5

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

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

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

您将在语法上将它与其他任何枚举非常相似地使用:

Animals.Dog
Run Code Online (Sandbox Code Playgroud)

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