C#强制静态字段初始化

时间:2016-01-11 16:29:22

标签: c# enums static initialization

我们目前正在实现某种基于字符串的“可扩展枚举类”。下面只显示了此C#代码的一部分,以使问题更易于理解。

如果我运行下面的代码,它会将“BaseValue1”和“BaseValue2”写入控制台。

如果我取消注释 RunClassConstructor 行并运行代码,它还会将“DerivedValue1”和“DerivedValue2”写入控制台。
这就是我想要实现的目标,但我想实现 RunClassConstructor 行。

我认为 DerivedEnum.AllKeys 会触发“DerivedValue1”和“DerivedValue2”的创建,但显然情况并非如此。

是否有可能实现我想要的目标,而不是强迫这些“枚举类”的用户编写一些魔术代码,或者进行某种虚拟初始化?

using System;
using System.Collections.Generic;

namespace ConsoleApplication
{
    public class Program
    {
        static void Main()
        {
            //System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(DerivedEnum).TypeHandle);

            foreach (var value in DerivedEnum.AllKeys)
            {
                Console.WriteLine(value);
            }
        }
    }

    public class BaseEnum
    {
        private static readonly IDictionary<string, BaseEnum> _dictionary = new Dictionary<string, BaseEnum>();

        public static ICollection<string> AllKeys
        {
            get
            {
                return _dictionary.Keys;
            }
        }

        public static readonly BaseEnum BaseValue1 = new BaseEnum("BaseValue1");
        public static readonly BaseEnum BaseValue2 = new BaseEnum("BaseValue2");

        protected BaseEnum(string value)
        {
            _dictionary[value] = this;
        }
    }

    public class DerivedEnum : BaseEnum
    {
        public static readonly DerivedEnum DerivedValue1 = new DerivedEnum("DerivedValue1");
        public static readonly DerivedEnum DerivedValue2 = new DerivedEnum("DerivedValue2");

        protected DerivedEnum(string value)
            : base(value)
        {
        }
    }
}

2 个答案:

答案 0 :(得分:2)

只有在首次访问类时才会调用静态构造函数。

虽然您使用了DerivedEnum.AllKeys,但它只是从BaseEnum继承而来。因此永远不会直接引用DerivedEnum

你可以做的一点是实际上在new static上创建一个DerivedEnum属性,该属性从基类返回相同的属性,因此在调用它时,将调用派生类的静态构造函数

public class DerivedEnum : BaseEnum
{
   public new static ICollection<string> AllKeys
   {
       get
       {
           return BaseEnum.AllKeys;
       }
   }
}

<强>更新

您还可以使用System.Reflexion动态调用它们:

public class BaseEnum
    static BaseEnum()
    {
        // from the types defined in current assembly
        Assembly.GetExecutingAssembly().DefinedTypes
            // for those who are BaseEnum or its derived
            .Where(x => typeof(BaseEnum).IsAssignableFrom(x))
            // invoke their static ctor
            .ToList().ForEach(x => System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(x.TypeHandle));
    }
}

您还可以使用此代码初始化其他程序集中定义的派生类:

AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(x => x.DefinedTypes)
    .Where(x => typeof(BaseEnum).IsAssignableFrom(x))
    .ToList().ForEach(x => System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(x.TypeHandle));

答案 1 :(得分:1)

在C#中,静态成员在第一次使用类之前初始化。在您的示例中,您实际上正在使用基类BaseEnum的成员并绕过DerivedEnum,这只会导致BaseEnum的静态成员被初始化。

您需要在派生类中实现AllKeys属性。这将确保编译器在派生类和&amp;中使用该属性。初始化所有成员。

然后在DerivedEnum中添加新的AllKeys属性,以覆盖AllKeys的{​​{1}}。

BaseEnum