Why is my static constructor not called?

In an effort to streamline the use of some utility code that we use for our different products I learned a lesson that I think not many programmers think about. And that is how the compiler, IntelliSense, inheritance and static methods work together.

The problem that I encountered was the following:
The utility code contains a print method that will traverse any object and print it out.
The print method has a bunch of overloads for various formatters and other stuff (this is not included in the sample code as this is trivial).
There exists other utility code that derives from the basic utility code to handle known objects in a non-generic way.
These derived utility methods should have all the overloads that only act as proxies for the real print implementation, available without the need for making signature hiding with the new keyword to get the right method called.
Any changes to the code must not break any old code using this utility code.

My starting point was code that looks like this:

namespace before
{
    using System;
    public class UtilClass
    {
        public static void Print(object data)
        {
            Print(data, true, 0);
        }

        public static void Print(object data, bool recurse)
        {
            Print(data, true, 0);
        }

        protected static void Print(object data, bool recurse, int depth)
        {
            Console.WriteLine(string.Format("Base class with data {0}", data));
        }
    }

    public class SpecificClass : UtilClass
    {
        new public static void Print(object data)
        {
            Print(data, true, 0);
        }

        new public static void Print(object data, bool recurse)
        {
            Print(data, true, 0);
        }

        new protected static void Print(object data, bool recurse, int depth)
        {
            Console.WriteLine(string.Format("Derived class with data {0}", data));
            UtilClass.Print(data, recurse);
        }
    }

    public class Program
    {
        static void Main()
        {
            UtilClass.Print("Call to Base");
            SpecificClass.Print("Call to Derived");
        }
    }
}

As you can see, all methods are static, and I thought that, hey, why not make some sort of Singleton implementation which is controlled by the specific utility implementation and make a virtual print method that gets called by the static code and can then be overridden by any of the specific implementations, as the execution context will always be only one of the specific implementations, this should not introduce any conflicts. Only one specific implementation would be active at a time.

So I made some changes to the original code and was quite surprised with what happened. The code looked like this:

namespace intend
{
    using System;

    public class UtilClass
    {
        protected static UtilClass instance = new UtilClass();
        public static void Print(object data)
        {
            instance.Print(data, true, 0);
        }

        public static void Print(object data, bool recurse)
        {
            instance.Print(data, recurse, 0);
        }

        protected virtual void Print(object data, bool recurse, int depth)
        {
            Console.WriteLine(string.Format("Base class with data {0}", data));
        }
    }

    public class SpecificClass : UtilClass
    {
        static SpecificClass()
        {
            instance = new SpecificClass();
        }

        protected override void Print(object data, bool recurse, int depth)
        {
            Console.WriteLine(string.Format("Derived class with data {0}", data));
            base.Print(data, true, 0);
        }
    }

    public class Program
    {
        static void Main()
        {
            UtilClass.Print("Call to Base");
            SpecificClass.Print("Call to Derived");
        }
    }
}

That's it, make the working methods to a virtual and an override, introduce an instance reference and make the type constructor update the instance reference to point to an object of the correct type. Remove the old overload methods from the specific implementation

What would you expect the outcome of the code from main is?

Base class with data Call to Base
Derived class with data Call to Derived
Base class with data Call to Derived

Or

Base class with data Call to Base
Base class with data Call to Derived

If you guessed the second output, then you are correct. And the reason: The type constructor for SpecificClass is never executed.

Why? Well the compiler makes some interpreting on the code, before spitting out IL. What the compiler sees is that the call to SpecificClass.Print is in fact a call to UtilClass.Print and will substitute the type, thus a reference to SpecificClass no longer exists, and the type constructor will never be called.

My final solution ended up being that I need to swallow the hit for the existing overloads and force any new code not to use these overloads by marking them obsolete.

The singleton idea is still valid, but I was not able to make the automatic selection of which flavor of the specialized class to use work with this way of implementing it.

The solution builds on a base class which has all the static void Print() overloads that is desired which work as proxies to the protected virtual instance method, and a protected singleton instance of itself for the proxies to call. Any existing derived classes will then have to stub out the already implemented static void print() with a setting of the flavor to a type of itself, and then calling the Print() on the instance. The end result looks a little something like this:

namespace Solution
{
    using System;

    public class UtilClass
    {
        protected static UtilClass instance = new UtilClass();

        public static void SetFlavor(T type) where T : UtilClass
        {
            UtilClass.instance = type;
        }

        public static void Print(object data)
        {
            instance.Print(data, true, 0);
        }

        public static void Print(object data, bool recurse)
        {
            instance.Print(data, recurse, 0);
        }

        protected virtual void Print(object data, bool recurse, int depth)
        {
            Console.WriteLine(string.Format("Base class with data {0}", data));
        }
    }

    public class SpecificClass : UtilClass
    {
        new public static void Print(object data)
        {
            SpecificClass.SetFlavor(new SpecificClass());
            (instance as SpecificClass).Print(data, true, 0);
        }

        new public static void Print(object data, bool recurse)
        {
            SpecificClass.SetFlavor(new SpecificClass());
            (instance as SpecificClass).Print(data, true, 0);
        }

        protected override void Print(object data, bool recurse, int depth)
        {
            Console.WriteLine(string.Format("Derived class with data {0}", data));
            base.Print(data, true, 0);
        }
    }

    public class Program
    {
        static void Main()
        {
            UtilClass.Print("Call to Base");
            SpecificClass.SetFlavor(new SpecificClass());
            SpecificClass.Print("Call to Derived");
        }
    }
}

If you have a more elegant solution than this, I would be happy se see your suggestion in the comments.


 

Some of the reading material I have read through to solve this mystery.

http://www.yoda.arachsys.com/csharp/beforefieldinit.html

http://ondotnet.com/pub/a/dotnet/2003/07/07/staticxtor.html

http://bytes.com/topic/c-sharp/answers/258322-static-constructor-derived-class

http://bytes.com/topic/c-sharp/answers/496182-invoking-static-constructors-base-classes

Comments