【问题标题】:Static Initializer/Constructor Ordering静态初始化器/构造器排序
【发布时间】:2014-01-08 17:56:45
【问题描述】:

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

解决方法是将#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 

}

【问题讨论】:

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


    【解决方案1】:

    让我们有类B,继承类A。经验法则是,当调用B 类的静态构造函数时,首先要确保其祖先类A 之前已初始化。 然而,当A 的静态构造函数被初始化时首先,它依赖于它的祖先B(无论如何这很奇怪),B 的静态构造函数不能在A 完成之前执行,这会导致任何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 时,顺序如下:

    Access A
        Invoke A's static constructor
            initialize A's static fields
            execute the constructor's code, which includes
                Access B and its static field B.Field
                    Invoke B's static constructor — circular dependency on A, cannot call
                    return B.Field which is uninitialized i.e. zero / null
                use invalid value of B.Field
    

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

    【讨论】:

    • 序列流对于查看正在发生的事情非常有帮助。但是在某些机器上,我上面发布的代码有效。在我的代码中,除了 A 之外,没有从任何地方访问 B,所以看起来某些机器 B 先访问并不只是运气。
    猜你喜欢
    • 1970-01-01
    • 2014-03-22
    • 2010-09-16
    • 2010-11-22
    • 1970-01-01
    • 2011-02-15
    • 1970-01-01
    • 2014-02-26
    • 1970-01-01
    相关资源
    最近更新 更多