Static Member Initialization Problem

Hello everyone... I finally got fed up with the built-in enums of .net so I decided to make something more intelligent by using classes with static members to feed dropdownlists. I'm running into some problems with static members initializing inside the child classes so I thought one of you guys would have an answer... The actual code is a bit more complex and hairy, but here is some simple and worthless code that will demonstrate my problem:

public class Child : Parent

{

public static Child Hello = new Child ("Hello");

private Child (string value):base(value){ } //Passing value to parent class to add to array

}

public abstract class Parent

{

static protected Hashtable hashOfValuesFromChildren = new Hashtable();

protected Parent (string value)

{

hashOfValuesFromChildren.Add(value, value);

}

public static string GetValues(string key)

{

return (string) hashOfValuesFromChildren[key];

}

}

Ok so now here's the problem... if I make a call in some function outside of these classes to Child.GetValues("hello");, I'll get an exception trown because they ke I'm using doesn't exist (even though it should). It doesn't seem to exist because the compiler doesn't actually intialize members of the Child class until some kind of reference is made to the Child class. Now you would think by calling Child.GetValues(), it would consider that as a reference right It doesn't because GetHashValues is actually in the Parent class and you are actually making a reference to the Parent class, not the Child class -- so child's members are never initialized. If I move the GetValues function from the Parent class to the Child class, everything works fine.

This appears to be some kind of compiler optimization, but I haven't been able to figure out how to get around it... The static constructor idea doesn't work because I never want nor need to create an instance of these Child classes... I just want to be able to call their static members directly. Any ideas/solutions



Answer this question

Static Member Initialization Problem

  • Mr_White

    This isn't exactly a compiler optimization. It's more that you've been tripped up by the C# compiler's attempt to be helpful.

    Fundamentally, the problem is that while C# makes it look like you can say "Call the static method define by this base class, but do it through the child class", the CLR doesn't actually offer such a construct. Static methods are always called on the class that defines them.

    So although C# lets you write:

    Child.GetValues("hello");

    this is actually the exact equivalent of writing:

    Parent.GetValues("hello");

    The fact that you can use the first syntax is really just a convenience feature offered by the C# compiler. But in this case, it hasn't been all that convenient, because it has misled you. It has allowed you to think "I have used the Child class" when in fact you haven't. You've only used the base class.

    (And of course, if you've only used the base class, it's not reasonable to expect the CLR to run all constructors of all derived classes for you: how is it supposed to discover the complete set of derived classes in the first place )

    You'll have to do something that really does use the Child class at the CLR level if you want its static constructor to run.


  • Troy Magennis

    Thanks for the gotcha... Let me ask you this, is there any attribute that I can use on the child class to tell the compiler to initialize the members upon project startup rather than on first reference
  • Deming

    Unfortunately no. Essentially what you want is a way of telling the CLR "Look at this class before you've been given a reason to look at it". In the general case there's clearly a bit of a bootstrap problem - the CLR is able to load assemblies from any arbitrary URL, so there's simply no way it can know at startup time the complete set of types that will eventually be used in your process. The set of types you might use at some point in the process lifetime is unbounded.

    Of course there's an obvious more attainable goal: initializing all relevant types in a particular assembly at the point at which that assembly is loaded.

    In principle the CLR would be able to support this: v2.0 introduced the concept of a 'module initializer' that runs when a particular module in a .NET assembly is loaded.

    However, as far as I know, C# does not support this feature in any way. (I believe it was mainly introduced for the benefit of C++/CLI - the old managed C++ compiler in vs2002/2003 had major issues surrounding DLL initialization.)

    So if you want a particular set of classes' static constructors to run, it's up to you to do something explicit to make that happen. The C# compiler doesn't offer any way of forcing a static constructor to run any earlier than the normal CLR rules of static initialization dictate, so your only options are to do things that trigger static initialization. (E.g. access some member of the class, or invoke a method that declares a variable of the type in question, or use a class that has a field of the type in question.)


  • Static Member Initialization Problem