2

This one's a little weird/complex and more just curiosity than anything.

I was looking for a way to make sure static calls from a base class could safely use static information set up in a derived class. I then noticed that C# allows me to call the derived class static constructor in the base class static constructor.

My question: Is is safe to call the derived class static constructor in the base class static constructor

Here is some sample code:

public abstract class Enumeration<TEnum, TValue>
    where TEnum : Enumeration<TEnum, TValue> // << Note the CRTP-ish thing
    where TValue: class
{
    private static readonly Dictionary<string, Enumeration<TEnum, TValue>> Mapping = new Dictionary<string, Enumeration<TEnum, TValue>>();
    public TValue Value { get; }
    public string Name { get; }

    // Base class calling derived static constructor. This sets up "Mapping" with derived class enumerations
    static Enumeration()
    {
        System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(TEnum).TypeHandle);
    }

    // Static member "Mapping" filled using this constructor when derived class statics are initialized
    protected Enumeration(TValue enumValue, string name)
    {
        Value = enumValue;
        Name = name;
        Mapping.Add(name, this);
    }

    // Uses "Mapping", so "Mappings" needs to be filled before this is called.
    protected static IEnumerable<TEnum> All => Mapping.Values.AsEnumerable().Cast<TEnum>();

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

public sealed class DerivedEnum : Enumeration<DerivedEnum, String>
{
    // This static member will input itself into the static "Mapping" in the base class
    public static readonly DerivedEnum A = new DerivedEnum("A", "A");

    private DerivedEnum(string val, string name) : base(val, name) {}
}

I have done several basic tests and it doesn't seem to break. Is there a way this could break?

Here is a fiddle if you need to... fiddle: https://dotnetfiddle.net/mREPyL

Also, my code is inspired by this answer. I wanted to see if I could get the derived classes more succinct.

Cory-G
  • 1,025
  • 14
  • 26
  • looks like calling `RunClassConstructor` twice will ignore the second call, so that doesn't appear to be a danger. – Cory-G Mar 21 '19 at 22:15
  • 2
    This whole thing really stinks. I can't think of a situation where you'd want the type to register itself with its base class, statically, when BaseClass is referenced somewhere. That sort of "magic" often gets people into tricky spots. It's going to be far more reliable to have a central registry which makes sure that all of the types are listed and registered; or iterate all types in the assembly, picke out the ones to be registered, and register them. At least the registration happens in a central deterministic place. – canton7 Mar 21 '19 at 22:22
  • 1
    @canton7 Yeah, not really looking to use this. It's mostly for my own learning. – Cory-G Mar 21 '19 at 22:24
  • 2
    The takeaway lesson should be that if you have to call `RuntimeHelpers.RunClassConstructor`, something's gone very, very badly. – canton7 Mar 21 '19 at 22:25
  • Aside from canton7's very valid point, why do you feel the need to invoke the static constructor of the type given as TEnum manually? The .NET runtime will call the static constructor of a type as part of the initializiation of that type. Before your code would be able execute anything involving any type used for TEnum, the runtime already would have initialized that type (including calling its static constructor). Type initialization is simply a prerequisite for using a type... –  Mar 21 '19 at 22:40
  • 1
    @elgonzo You would think. Sadly, the static enum members of the derived class are not set up when just calling the static base functions. Here is a fiddle: https://dotnetfiddle.net/QMlSsU It throws an exception unless you comment in either the use of A or the base-constructor call to the derived constructor. My code is taken from this guy's, which required overrides in the derived class to avoid this issue: https://stackoverflow.com/a/8353191/1884803 – Cory-G Mar 21 '19 at 22:51
  • Oh, that's interesting. The curiously recurring template pattern... hmm... –  Mar 21 '19 at 23:09

0 Answers0