2010-12-22 59 views
223

请向我解释静态构造函数的用法。为什么和什么时候我们会创建一个静态构造函数,并且有可能重载一个?静态构造函数的用途是什么?

+1

应当指出的是,有建设的静态方法(对于一个例子,仰望[Singleton设计模式(http://stackoverflow.com/questions/7095/is -the-c-sharp-static-constructor-thread-safe)),它们被用来隐藏用于实例化类的实际构造函数。这给了作者更多的关于如何使用他们的类的控制。 – Izzy 2013-04-19 10:09:29

回答

186

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

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

+3

感谢您的回复。你能否给我提供关于你的句子的更多细节“除非你滥用反射,它保证最多只能运行一次”..对于静态构造函数可以做什么反射.. – 2010-12-22 07:27:28

+19

@Rajesh - 找到方法并调用`Invoke` 20倍。 – 2010-12-22 07:32:17

+0

嗨@MarcGravell,请说明CLR2和CLR4静态构造函数的行为有什么区别。而且,这是否意味着静态构造函数是线程安全的? – 2013-05-21 09:37:46

91

Static Constructors (C# Programming Guide)

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

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

  • 静态构造函数并不需要访问修饰符或有参数。

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

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

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

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

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

7

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

8

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

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

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

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

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

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

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

69

静态构造函数也是,当你有依赖静态字段非常有用彼此之间,使得初始化的顺序很重要。如果您通过格式化程序/美化程序运行代码来更改字段的顺序,那么您可能会发现自己的空值不在您希望的位置。

例:假设我们有这个类:

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

当您访问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"; 
} 

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; 

    } 
} 

现在,无论你有什么样的顺序领域,初始化永远是正确的。

1

静态构造函数

构造函数声明使用static修饰符是一个静态构造函数。静态构造函数用于初始化静态数据或执行需要在类的生命周期中仅执行一次的特定操作。静态构造函数是在类中执行的第一个代码块。静态构造函数在类的生命周期中只执行一次。它被自动调用。静态构造函数不接受任何参数。它没有访问说明符。它不直接调用。

3

为什么和什么时候我们会创建一个静态构造函数...?

其中一个特定使用静态构造函数的原因是创建一个'超级枚举'类。这里有一个(简单的,做作)例如:

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语句中使用这些值(因为它需要不变的值)。

相关问题