C # static field initialization

We are currently implementing some kind of "extensible class enum" based on strings. Only part of this C # code is below to facilitate understanding of the problem.

If I run the code below, it writes "BaseValue1" and "BaseValue2" to the console.

If I uncomment the RunClassConstructor line and run the code, it additionally writes "DerivedValue1" and "DerivedValue2" to the console.
This is what I want to achieve, but I want to achieve it without the RunClassConstructor line .

I thought DerivedEnum.AllKeys would lead to the creation of "DerivedValue1" and "DerivedValue2", but obviously this is not the case.

Is it possible to achieve what I want without forcing the user of these "enum classes" to write some kind of magic code or do some kind of fictitious initialization?

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)
        {
        }
    }
}
+4
source share
2 answers

The static constructor is launched only on the first call to the class.

So far you have used DerivedEnum.AllKeys, but it is just inherited from BaseEnum. Therefore, they DerivedEnumnever referred directly.

A small hack that you could do is actually create a property new staticon DerivedEnumthat returns the same property from the base class, so when you call it, the static constructor of the derived class will be called.

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

UPDATE

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));
+2

# . BaseEnum DerivedEnum, BaseEnum.

AllKeys . , .

AllKeys DerivedEnum, AllKeys BaseEnum.

new public static ICollection<string> AllKeys
{
    get
    {    
        return BaseEnum.AllKeys;
    }
}
+1

Source: https://habr.com/ru/post/1623795/