我今天遇到了一个有趣的错误,下面的代码会在某些机器上的注释行上崩溃,而不会在其他机器上崩溃。问题似乎与静态构造函数的排序,静态初始化程序和继承有关。
修复是将#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
}
答案 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
您提取区域中包含的代码的解决方案非常符合逻辑,无论如何都应该这样做,因为关注点分离。