几周前,我从Java切换到C#。今天,我有一个奇怪的行为,我尝试在这个简单的样本中重现它。我正在使用.net FW 4。
我有三节课: 首先,抽象的一个:
namespace ReadonlyStaticOrder
{
using System;
using System.Collections.Generic;
public abstract class AbstractClass
{
public AbstractClass(string value, IEnumerable<string> someValues)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (someValues == null)
{
throw new ArgumentNullException("someValues");
}
// would do something after...
}
}
}
第二个:
namespace ReadonlyStaticOrder
{
using System.Collections.Generic;
public sealed class ReadonlyOrderInitialization : AbstractClass
{
// this line introduces the bug, since it call the ctor before SomeValues already initialized
// if removed, no more exception
public static readonly ReadonlyOrderInitialization Sample = new ReadonlyOrderInitialization("sample");
private static readonly IEnumerable<string> SomeValues = new string[] { "one", "two", "three" };
public ReadonlyOrderInitialization(string value)
: base(value, SomeValues)
{
}
}
}
示威者:
namespace ReadonlyStaticOrder
{
using System;
public sealed class Program
{
static void Main(string[] args)
{
try
{
new ReadonlyOrderInitialization("test");
}
catch (TypeInitializationException typeInitializationException)
{
Console.WriteLine(typeInitializationException.Message);
Console.WriteLine(typeInitializationException.InnerException.Message);
Console.WriteLine(typeInitializationException.StackTrace);
}
Console.ReadLine();
}
}
}
输出是:
的类型初始值设定项 'ReadonlyStaticOrder.ReadonlyOrderInitialization'引发了异常。 值不能为空。参数名称:someValues at ReadonlyStaticOrder.ReadonlyOrderInitialization..ctor(String value)
在ReadonlyStaticOrder.Program.Main(String [] args)中 d:\计算器\静 readonlyissue \ ConsoleApplication1 \ ReadonlyStaticOrder \的Program.cs:行 12
我在引入错误的行上添加了评论。对我来说,编译器必须警告我,由于静态初始化的顺序,行为可能很奇怪。我错了吗?
谢谢你们,我希望你们有足够的信息。
答案 0 :(得分:5)
定义为文本顺序 - ECMA 334中的§17.11:
如果一个类包含带有初始值设定项的任何静态字段,那么这些初始值设定项会在执行静态构造函数之前立即以文本顺序执行。
另外,如果您考虑partial classes
,in which case : it is not defined,这会让特别感兴趣。
如果有疑问,请将初始化显式移动到静态构造函数。
至于为什么;考虑(注意:这些只是我自己的想法):
partial classes
问题,未严格定义完整订单本身;所以它不能处理一般情况 - 再次,覆盖特定的案例(单个类片段等)回到“薄单板”(它仅警告明显的情况,但不能帮助非平凡的事情)答案 1 :(得分:1)
通常,如果您在初始化之前尝试使用成员,编译器会发出警告。
在这种情况下,您绕过此检查,因为静态成员不直接使用其他静态成员,而是调用使用另一个静态成员的构造函数。
编译器无法保护您免受所有可能的依赖性问题的影响,只能保护简单的依赖性问题。对于编译器而言,这只是一个过于复杂的步骤。
编译器当然可以可能来捕获这样的东西,但是这会使每个附加级别的依赖变得更加复杂,并且仍然无法捕获每个 情况。