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


当前回答

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

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

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

其他回答

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

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

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;

    }
}

现在,不管字段的顺序是什么,初始化总是正确的。

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

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

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

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

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

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

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

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

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

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

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

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

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