C# 静态参数的初始化顺序

C# 静态参数的初始化顺序,c#,.net,compiler-construction,initialization,C#,.net,Compiler Construction,Initialization,几周前,我从Java转到了C。今天,我有一个奇怪的行为,我试图在这个简单的样本中重现它。我用的是.NETFW4 我有三门课: 首先,抽象的一点: namespace ReadonlyStaticOrder { using System; using System.Collections.Generic; public abstract class AbstractClass { public AbstractClass(string value,

几周前,我从Java转到了C。今天,我有一个奇怪的行为,我试图在这个简单的样本中重现它。我用的是.NETFW4

我有三门课: 首先,抽象的一点:

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...
        }
    }
}
输出为:

的类型初始值设定项 “ReadonlyStaticOrder.ReadonlyOrderInitialization”引发异常。 值不能为null。参数名称:someValues at ReadOnlyStatiOrder.ReadonlyOrderInitialization..ctor(字符串值)
在中的ReadOnlyStatiOrder.Program.Main(字符串[]args)处 d:\stackoverflow\static ReadOnlySue\ConsoleApplication1\ReadonlyStaticOrder\Program.cs:line 十二,

我在介绍bug的那一行添加了一条注释。对我来说,编译器必须警告我,由于静态初始化的顺序,这种行为可能会很奇怪。我错了吗


谢谢大家,我希望你们有足够的信息。

通常,如果您试图在初始化成员之前使用它们,编译器会发出警告

在这种情况下,您可以绕过此检查,因为静态成员不直接使用另一个静态成员,而是调用使用另一个静态成员的构造函数

编译器不能保护您免受所有可能的依赖性问题的影响,只有那些简单的问题。对于编译器来说,这只是一个过于复杂的步骤


当然,编译器可以捕获类似的内容,但这会使每一个附加的依赖级别都变得更加复杂,并且仍然不可能捕获所有情况。

它被定义为ECMA 334中的文本顺序-§17.11:

如果一个类包含任何带有初始值设定项的静态字段,则这些初始值设定项将在执行静态构造函数之前以文本顺序执行

顺便说一下,如果您考虑部分类< /COD>,

,这将变得特别有趣。 如果有疑问,请将初始化显式移动到静态构造函数


为什么,;考虑(注:这些只是我自己的想法):

  • “确定赋值”通常会阻止这一问题,但“确定赋值”不适用于字段
  • 全面详细地分析代码在计算上是复杂的(我认为可能是“暂停”),因此它只能提供一个不完整的安全外表(这是人为的,在任何非平凡的场景中都可能导致问题)
  • 由于
    部分类
    问题,完整订单本身没有严格定义;因此,它不能处理一般情况,而且,覆盖特定情况(单个类片段等)又回到了“薄薄的表面”(它只对明显的情况发出警告,而对非琐碎的情况则无能为力)

我不确定你的问题是什么。很抱歉。这里有一个更好的表述方法:当静态类型初始化之间的循环依赖关系会导致意外行为时,编译器为什么不警告我?@Avanbelle我将在我的答案中添加一些“为什么”的想法……谢谢你的回答。我知道顺序,但并不知道编译器没有捕捉到它。在标记您的答案OK之前,我想尝试用Java编写这段代码,并使用Eclipse编译器构建它。我将与您保持联系。@Avanbelle有关信息,我刚刚通过“mono”编译器(
gmcs
)测试了一个简单的示例-没有警告,并且严格按照文本顺序:
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();
        }
    }
}