So static constructors are weird.  This should be an unconstroversial statement, but in case anyone was in doubt and needed more evidence, here’s a peculiar little situation.  I normally use static constants in any project where I need immutable references to strings, numerical constants, or other objects.

So I’ve set up a static ‘Constants’ class, which has some static readonly strings and some dictionaries which references those strings:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace StaticStringsWeirdness
{
    static class Constants
    {
        public static readonly string PlanKey = "Plan";
        public static readonly Dictionary FridayNightPlans = 
            new Dictionary {
                                            {PlanKey,Party}
                                          };
        private static readonly string Hack = "Hackety hack!";
        private static readonly string Party = "Party! Oontz oontz oontz!";
        public static readonly Dictionary SaturdayNightPlans = new Dictionary {
                                            {PlanKey,Hack}
                                          };
 
    }
}

Pretty straight forward. I’m planning to party on Friday night and buckle down and do some hacking on Saturday night. (Sounds like a damned fine weekend to me!) So I have two dictionaries, one for my plans Friday night and one for my plans Saturday night. I also have some strings that are private and used to build the dictionaries. Anyway, both of these dictionaries are initialized in exactly the same fashion. They both use private static strings that are defined in the same class and same code file to add a single entry, keyed to the string “Plan”.

Anyone want to bet that both dictionaries get initialized with the right values? Anyone? C’mon, 5 gets you 10 if those two dictionaries both get initialized properly.

If you took that bet, email me and I’ll let you know where you can send your $5.

See, I use these two dictionaries in a simple little C# console app. There’s no trickery here, nor really even anything interesting. I just grab the value associated with the “Plan” key and dump it to the console. Both dictionaries have this key, and both of them assigned to it a private static readonly string. Code for the app:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace StaticStringsWeirdness
{
    class Program
    {
        static void Main(string[] args)
        {
            //Friday night
            Console.WriteLine("Whatcha doin' Friday night?");
            Console.WriteLine(Constants.FridayNightPlans[Constants.PlanKey]);
 
            //Saturday night
            Console.WriteLine("That's cool. What about Saturday night?");
            Console.WriteLine(Constants.SaturdayNightPlans[Constants.PlanKey]);
        }
    }
}

So now you would expect this to just output a cute little story about how my plans are to party on Friday night and to hack on Saturday night. Instead, the output looks like:

Whatcha doin' Friday night?
 
That's cool. What about Saturday night?
Hackety hack!
Press any key to continue . . .

So the output from the first dictionary, which should have read “Party! Oontz oontz oontz!” was instead the empty string. It threw no exceptions, and the request for the value keyed to the “Plan” key returned a string that is initialized, but contains the empty string. The second dictionary, however, returns the expected value.

So why the difference in behavior between the two dictionaries? Well, if you look at the Constants.cs code listing, you’ll see that the FridayNight dictionary is declared above the Hack and Party strings and that the SaturdayNight dictionary is declared below them. This means that, when the constants class is loaded, the FridayNight dictionary is initialized first (using an empty string for Party), followed by the Hack and Party strings, and then the SaturdayNight dictionary (which gets the correct value for the Hack string).

Again, the value in the FridayNight dictionary is not null. The string object it references has been created, but has been initialized to the empty string. This is because the static class is created with all of its members. These members are created with the default values for their type, which for a string is the empty string. Then, during the static constructor, these get initialized in the order that they appear in the code file. You can see this clearly by looking at the static constructor that was generated by the C# compiler.

1
2
3
4
5
6
7
8
9
10
11
12
static Constants()
{
    PlanKey = "Plan";
    Dictionary g__initLocal0 = new Dictionary();
    g__initLocal0.Add(PlanKey, Party);
    FridayNightPlans = g__initLocal0;
    Hack = "Hackety hack!";
    Party = "Party! Oontz oontz oontz!";
    Dictionary g__initLocal1 = new Dictionary();
    g__initLocal1.Add(PlanKey, Hack);
    SaturdayNightPlans = g__initLocal1;
}

You’ll notice that none of the members (Hack, Party, FridayNight, SaturdayNight) are actually created in the constructor. They exist already and, at the start of the static constructor, have the default values for their types. In the case of strings like Hack and Party, that’s the empty string. The FridayNight dictionary gets built just fine, but with an empty string instead of the expected “Party! Oontz oontz oontz!”.

So where FridayNight should have been full of partying, it was instead full of fail.

The moral of the story is that, while static classes are handy, they do take some care. This is especially true when it comes to their constructors. If you need to use references to other class members in static initializers (as I did with the dictionaries above), be sure that the objects that are referenced are declared above the static initializer of the member that references them. Otherwise the referenced object will have its default value at the time that it’s used in the initializer.