具有圆形静态只读字段定义的奇怪行为

时间:2019-01-15 10:29:17

标签: c# instantiation

在Visual Studio 2017(Debug build)中运行以下代码时,我有一些奇怪的行为:

using System;
using System.Collections.Generic;

namespace ConsoleApp2
{
    public class Program
    {
        public static class DefaultCustomers
        {
            public static readonly Customer NiceCustomer = new Customer() { Name = "Mr. Nice Guy " };
            public static readonly Customer EvilCustomer = new Customer() { Name = "Mr. Evil Guy " };
            public static readonly Customer BrokeCustomer = new Customer() { Name = "Mr. Broke Guy" };
        }

        public class Customer
        {
            public static readonly IEnumerable<Customer> UnwantedCustomers = new[] { DefaultCustomers.EvilCustomer, DefaultCustomers.BrokeCustomer };

            public string Name { get; set; }

            public override string ToString()
            {
                return Name;
            }
        }

        public static void Main(string[] args)
        {
            Console.WriteLine(new Customer() { Name = "Some other customer" });
            //Console.WriteLine(DefaultCustomers.NiceCustomer);

            foreach (var customer in Customer.UnwantedCustomers)
            {
                Console.WriteLine(customer != null ? customer.ToString() : "null");
            }

            Console.ReadLine();
        }
    }
}

控制台上的输出是

Some other customer
Mr. Evil Guy
Mr. Broke Guy

这大致是我预期的行为。但是,如果取消注释Program.Main(...)中的第二行,则输出将更改为

Some other customer
Mr. Nice Guy
null
null

我知道可以通过将UnwantedCustomers转换为静态readonly属性来轻松解决此问题。

但是我不知道所描述的行为是否遵循类和对象的初始化顺序,或者该行为是否未定义?

1 个答案:

答案 0 :(得分:6)

您有一个初始化问题。

static字段(和属性)在静态构造函数运行之前初始化(如果有,则将运行)。这是在引用对类的任何成员的引用之前(无论是否静态)。

注释掉石灰后,在引用Customer.UnwantedCustomers时会触发Customer的静态构造,然后触发DefaultCustomers的静态构造。

但是通过更容易地引用DefaultCustomers,它会触发DefaultCustomers的静态构造,这需要Customer的静态构造。这意味着Customer的静态属性在DefaultConstomers的静态属性之前被初始化。并且因此为null。在这种情况下,Customer的静态构造完成后,DefaultCustomers的静态构造将完成,因此DefaultCustomers.NiceCustomer具有一个值,但是Customer.UnwantedCustomers包含空值。

这是定义明确的行为,以无帮助的可预测行为来涵盖此类情况。

您的问题是两种类型之间的循环引用。将UnwantedCustomers设置为DefaultCustomers的字段可以避免此问题。