静态初始化器/构造函数排序

时间:2014-01-08 17:56:46

标签: c# inheritance static-members static-initialization static-constructor

我今天遇到了一个有趣的错误,下面的代码会在某些机器上的注释行上崩溃,而不会在其他机器上崩溃。问题似乎与静态构造函数的排序,静态初始化程序和继承有关。

修复是将#region中的代码移动到另一个类中,但我仍然不明白实际发生了什么,以及为什么它似乎只发生在某些机器上。

我看过这两个问题:
http://csharpindepth.com/Articles/General/Singleton.aspx http://csharpindepth.com/Articles/General/BeforeFieldInit.aspx

它提供了一些见解,但都没有涉及遗产如何影响事物。

public class CountAggregator : Aggregator
{
    private static readonly CountAggregator _instance = new CountAggregator();

    public static CountAggregator Instance
    {
        get
        {
            return _instance; 
        }
    }

    private CountAggregator() : base("CNT")
    {
    }

}



public class Aggregator
{

    protected Aggregator(string id)
    {
        Id = id;
    }

    public string Id { get; private set; }





    #region All Aggregators

    private static readonly List<Aggregator> _allAggregators = new List<Aggregator>();
    private static readonly Dictionary<string, Aggregator> _aggregatorsById = new Dictionary<string, Aggregator>();

    public static IEnumerable<Aggregator> All
    {
        get { return _allAggregators; }
    }

    public static Aggregator GetAggregator(string id)
    {
        return _aggregatorsById[id];
    }

    static Aggregator()
    {
        _allAggregators.AddRange(new Aggregator[]
        {
             CountAggregator.Instance,
        }

        foreach (var aggregator in _allAggregators)
        {
            //this prints false, and the next line crashes
            HtmlPage.Window.Alert((aggregator != null).ToString());
            _aggregatorsById.Add(aggregator.Id, aggregator);                
        }        
    }

    #endregion 

}

1 个答案:

答案 0 :(得分:2)

让我们有一个班级B,继承班级A。经验法则是,当调用类B的静态构造函数时,它首先确保其祖先类A之前被初始化。 然而,当A的静态构造函数初始化 first 时,依赖于它的祖先B(这无论如何都很奇怪),{{ 1}}的静态构造函数无法在B完成之前执行,这导致任何A的字段都处于默认状态(= 0,null)状态。

首次访问代码中的任何位置B时,顺序如下:

B

另一方面,当您首次在代码中的任何位置访问Access B Invoke B's static constructor Invoke A's static constructor, if necessary initialize A's static fields execute the constructor's code initialize B's static fields execute the constructor's code 时,顺序如下:

A

您提取区域中包含的代码的解决方案非常符合逻辑,无论如何都应该这样做,因为关注点分离。