静态参数初始化的顺序
本文关键字:顺序 初始化 参数 静态 | 更新日期: 2023-09-27 18:18:24
几个星期前,我从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 atReadonlyStaticOrder.ReadonlyOrderInitialization . .男星(字符串值)
在ReadonlyStaticOrder.Program。Main(String[] args) ind: ' ' stackoverflow静态的readonlyissue ' ConsoleApplication1 ' ReadonlyStaticOrder ' Program.cs:行12
我在介绍bug的那一行添加了注释。对我来说,编译器必须警告我,由于静态初始化的顺序,这种行为可能会很奇怪。我错了吗?
谢谢大家,我希望你们有足够的信息。
定义为ECMA 334中§17.11的文本命令:
如果类包含任何带初始化项的静态字段,则这些初始化项在执行静态构造函数之前按文本顺序执行。
作为题外话,如果您考虑partial classes
,这会使特别有趣,在这种情况下:它没有定义。
如果有疑问,将初始化显式移动到静态构造函数。
至于为什么;考虑一下(注意:这些只是我自己的想法):
- "明确赋值"通常会阻止这个问题,但是"明确赋值"不适用于字段
- 详细分析代码在计算上是复杂的(我想"停止",也许)-所以它只能提供一个不完整的安全表面(这是人为的,可能导致任何重要场景中的问题)
- ,由于
partial classes
的问题,完整顺序本身没有严格定义;所以它不能处理一般情况-再一次,覆盖特定的情况(单个类片段等)是回到"薄贴面"(它只警告明显的情况,但不能帮助非平凡的)
通常情况下,如果你试图在成员初始化之前使用它们,编译器会警告你。
在这种情况下,您绕过了此检查,因为静态成员不直接使用另一个静态成员,而是调用使用另一个静态成员的构造函数。
编译器不能保护你避免所有可能的依赖问题,只能保护那些简单的。这一步太复杂了,编译器无法捕捉到。
对于编译器来说,当然可以捕获像这样的东西,但是这会使每一个额外的依赖级别变得更加复杂,并且仍然不可能捕获每一个情况。