Static constructors, part one

Previously on FAIC we saw how easy it was to deadlock a program by trying to do something interesting in a static constructor.[1. Static constructors are also called “class constructors”. Since the actual method generated has the name .cctor they are often also called “cctors”. Since “static constructor” is the jargon used in the C# specification, that’s what I’ll stick to.] Static constructors and destructors[2. Astonishingly, I've never blogged about how difficult it is to write a correct destructor, though it has come up on StackOverflow. That's a good topic for a future fabulous adventure.] are the two really weird kinds of methods, and you should do as little as possible in them.

Before I expound further on that topic though, a look at how static constructors work is in order. And before I do that, it’s probably a good idea that you get a refresher on how instance constructors work. My article “Why do initializers run in the opposite order of constructors?” provides a detailed look at constructor semantics, so maybe check that out if you have a few minutes. Part one is here and part two is here.

OK, now that you know how instance constructors work, let’s dig into static constructors. The idea is pretty simple: a static constructor is triggered to run immediately before the first static method on its class is called, or immediately before the first instance of its class is created. As we saw previously, the runtime tracks when a static constructor is “in flight” and uses that mechanism to ensure that each static constructor is invoked no more than once.

Now that you know all of that, you can predict the output of this simple program:

using System;
class B
{
  static B() { Console.WriteLine("B cctor"); }
  public B() { Console.WriteLine("B ctor"); }
  public static void M() { Console.WriteLine("B.M"); }
}
class D : B
{
  static D() { Console.WriteLine("D cctor"); }
  public D() { Console.WriteLine("D ctor"); }
  public static void N() { Console.WriteLine("D.N"); }
}
class P 
{
  static void Main()
  {
    System.Console.WriteLine("Main");
    new D();
  }  
}

We know that B’s instance constructor must be invoked before D’s instance constructor, and we know that D’s static constructor must be invoked before D’s instance constructor. The only interesting question here is “when will B’s static constructor be invoked?” An instance of D is also an instance of B, so B’s static constructor has to be invoked at some point.

As you know from reading my article on instance constructors, what actually happens is that the compiler generates D’s instance constructor so that the first thing it does is call B’s instance constructor; that’s how we get the appearance that B’s instance constructor runs first. Thus, the actual order of events here can be best conceptualized like this:

  • Main starts. It prints out its message and then tries to invoke D’s instance constructor on a new instance of D.
  • The runtime detects that D’s instance constructor is about to be invoked, so it invokes D’s static constructor.
  • D’s instance constructor invokes B’s instance constructor. The runtime detects that, so it invokes B’s static constructor.
  • B’s instance constructor runs and returns control to D’s instance constructor, which finishes normally.

Pretty straightforward. Let’s mix it up a little.


Next time on FAIC: A brief digression for fun on a Friday. Then next week we’ll resume this series and take a look at a few less straightforward cases.

About these ads

18 thoughts on “Static constructors, part one

    • That reminds me of a question I pondered when first learning about C# generics: can you do a static analysis to find a finite set of type instantiations that includes all those used at runtime?

      And I found the answer to be “no,” because the set can be infinite:

      class Mayhem
      {
      public static int x = Mayhem<Mayhem>.x;
      }
      class MainClass
      {
      public static void Main(string[] args)
      {
      Console.WriteLine(Mayhem.x);
      }
      }

      Though I suspect you could find a finite set for most programs.

      • Actually, the definition should be:

        class Mayham
        {
        public static int x = Mayham<Mayham>.x;
        // …
        }

        so you can’t construct such an infinite type (at least this way).

        • Oh how I love HTML… :) So I was trying to write:

          class Mayham<T>
          {
              public static int x = Mayham<Mayham<???>>.x;
              // …
          }

  1. Generally, I try to avoid all static anything in my code. It reduces testability, often induces tighter coupling between components, and breaks of the OO model, and is a potential source of concurrency issues.

    Even constructors fall into this trap. In most so-called OO languages, these can’t be avoided though, unfortunately. Gilad Bracha has an excellent article on the reasoning here: http://gbracha.blogspot.co.uk/2007/06/constructors-considered-harmful.html

    • To my mind, constructors have two aspects: a static aspect which is invoked by code which says “foo = new Bar();” and an instance aspect which may invoked by the class’s static aspect or by a subclass instance constructor. There’s no logical reason the visibility of these aspects should be related, beyond the fact that .net has no mechanism to separate them. It would be reasonable for an inheritable class to have a constructor which is only supposed to be used for producing base-type instances and a different constructor which is only supposed to be used for producing derived-type instances, but there’s no way to express such concepts. Interestingly, the static aspect of parameter-less constructors is the only static aspect of any class which is invokable via generic type parameter.

  2. Calling an instance method (on a null target, either via reflection or by using the call opcode directly in IL) also appears to force the static constructor to be called, even if no instance is ever created and no static member is accessed (though I’m not sure this is what the CLI spec mandates).

  3. This lazy invoking of static constructors explains a bit about why one particular optimization I use works. I tend to use static constructors for things like establishing dynamic methods to avoid reflecting members in high frequency code. One of the optimizations to this was to have a method in main invoke constructors from each class that did that so that it would build the static data before entering the main loop.

  4. Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1290

  5. Pingback: The Daily Six Pack: February 9, 2013 | Dirk Strauss

  6. Pingback: Cheatsheet: 2013 02.01 ~ 02.15 - gOODiDEA.NET

  7. Pingback: Be careful with static classes « Jim's Random Notes

  8. “…a static constructor is triggered to run immediately before the first static method on its class is called, or immediately before the first instance of its class is created.”

    I was under the impression that the standard doesn’t include anything about “immediately”? It would be perfectly valid (even if not sensible) to call static constructors at “any time” between start of program until actual access/constructor?

    Did this change? It it guaranteed that a static constructor of a class is never “just called”, but only “immediately” before calling the first static thingie or creating the first instance?

    Or is it just how all currently known implementations work?

  9. Really Nice article on static constructor!
    I have a question here.

    Is there a specific reason for order of execution of static constructors? as we see that derived class static constructor is invoked before base class static constructor which is reverse of instance constructor.

  10. Pingback: CLR week on the Old New Thing has started: first one about Static Constructors « The Wiert Corner – irregular stream of stuff

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s