静态参数初始化的顺序

本文关键字:顺序 初始化 参数 静态 | 更新日期: 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的问题,完整顺序本身没有严格定义;所以它不能处理一般情况-再一次,覆盖特定的情况(单个类片段等)是回到"薄贴面"(它只警告明显的情况,但不能帮助非平凡的)

通常情况下,如果你试图在成员初始化之前使用它们,编译器会警告你。

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

编译器不能保护你避免所有可能的依赖问题,只能保护那些简单的。这一步太复杂了,编译器无法捕捉到。

对于编译器来说,当然可以捕获像这样的东西,但是这会使每一个额外的依赖级别变得更加复杂,并且仍然不可能捕获每一个情况。