I am writing this blog entry as a reminder to myself to be careful when using static fields or properties, and I wanted to document some silliness on my part for posterity. Recently I was working on some code where I wanted to keep track of derived class instances by storing them in a static list in the base class. The classes I was working on were non-trivial and fairly complex (and the original versions were not even authored by me). So for the sake of this blog entry, I’ve come up with simplified base and derived classes to explain what happened. Here’s what the base class looked like :
class Base
{
private static List list = new List();
public static List List
{
get { return Base.list; }
}
private Base()
{
Base.list.Add(this);
}
public string Name { get; private set; }
public Base(string name) : this()
{
this.Name = name;
}
}
And here’s what a typical derived class would be like :
class Derived : Base
{
public static Derived Nish = new Derived("Nish");
public static Derived Andrew = new Derived("Andrew");
public static Derived Megan = new Derived("Megan");
public Derived(string name) : base(name)
{
}
}
I thought it was all good, and then ran some code that did an iteration of the list :
foreach (Base item in Derived.List)
{
Console.WriteLine(item.Name);
}
To my tremendous surprise nothing came up and the list was empty. For a full 10 minutes, the idiot that I am, I kept pondering over this and wondering what the heck was going on. Then it hit me just like that. Even though I was accessing Derived.List, that was just a C# syntactic convenience that allowed me to write it that way because Derived did not have a List member at all (the compiler auto-fixes this to Base.List in the generated MSIL). The property was defined on Base, and thus Derived has not been accessed yet when I iterate Derived.List. So Derived‘s static initialization has not even happened yet. Once I realized my folly, fixing it was straight forward, I had to bring down the List property to the Derived class. This meant that every derived class had to do that which was a bit of an annoyance but not so much as to be a show stopper. Here’s the correct code (for my simplified example) :
class Base
{
protected static List list = new List();
private Base()
{
Base.list.Add(this);
}
public string Name { get; private set; }
public Base(string name) : this()
{
this.Name = name;
}
}
class Derived : Base
{
public static Derived Nish = new Derived("Nish");
public static Derived Andrew = new Derived("Andrew");
public static Derived Megan = new Derived("Megan");
public Derived(string name) : base(name)
{
}
public static List List
{
get { return Base.list; }
}
}
Next time you are using static properties in your base classes, just be a little careful – I know I’ll be.
Read Full Post »