AddThis Social Bookmark Button

Print

Static Constructors Demystified

by Satya Komatineni
07/07/2003

Static classes in C# are an important tool that most developers should know how to use effectively. The confusion usually surfaces when dealing with static constructors to set up a static class. Static constructors can be used to initialize classes, utilities, and even singletons. Understanding some of the issues surrounding static constructors, like beforeFieldInit and static field initialization, will help you effectively use static initialization features of your static class.

A Quick Example


public class UtilityClass
{
  //
  // Resources
  //

  // r1 will be initialized by the static constructor
  static Resource1 r1 = null;

  // r2 will be initialized first as static constructors are 
  // invoked after the static variables are initialized
  static Resource2 r2 = new Resource2();

  //Notice how there is no public modifier
  //Access modifiers are not allowed on static constructors
  static UtilityClass()
  {
    r1 = new Resource1();
  }

  static void f1(){}
  static void f2(){}
}

Introduction

Resource initialization is a common occurrence in programming. I have seen many libraries in different languages where a developer has to explicitly initialize a facility before starting to use the library. In most object-oriented languages, this problem is tackled using static variables and constructors that get called in response to the instantiation of those static variables.

C#, while retaining this ability to use static variables for initialization, also provides a language construct called the "static constructor." Static constructors provide a clean way to solve the initialization problems in C# programs.

Let me explore an initialization example to illustrate the various aspects of static constructors. Imagine a case where you are writing a utility class with a set of public static functions. The intention is that other programmers can use these static functions in their programs without explicitly instantiating the class.


public class UtilityClass
{
  public static void f1(){}
  public static void f2(){}
}

Resources as Static Variables

If these functions require some resources that need to be acquired at the start and kept for the life of the program, then there needs to be a way to initialize these resources. To demonstrate this case let me add a resource variable called r1 of type Resource1 to this UtilityClass. Let us initially set the resource to null while we decide on a good way to initialize it. At this stage, the modified class will look like this:


public class UtilityClass
{

  //Resources
  static Resource1 r1 = null;

  static void f1(){}
  static void f2(){}
}

Resource Initialization Using Inline Instantiation of Static Objects

One of the ways to initialize this resource to other than null is to directly instantiate the Resource1 inline. The following code demonstrates the common practice of newing classes for static variables inline wherever the static variables are defined.


public class UtilityClass
{

  //Resources
  static Resource1 r1 = new Resource1();

  static void f1(){}
  static void f2(){}
}

Related Reading

Programming C#
By Jesse Liberty

This is called static field initialization, where field r1 of type Resource1 is initialized. We are encouraged to do this because, intuitively, we argued with ourselves that this initialization will happen before any of the other static functions are called. So if f1() or f2() is to be called, there is an assumption that r1 should have been initialized by then. But read on to find otherwise.

beforeFieldInit: The Fly in the Ointment

There is an exception to this perfect rule. If this class is marked as beforeFieldInit, then r1 may not be initialized when the functions are called. According to the CLI, "beforeFieldInit specifies that calling static methods of the type does not force the system to initialize the type." This means that the static variables are not initialized just because we called a static function. But CLI does insist that all of the field variables will be initialized as soon as one of the static fields is accessed. So if we are depending on some side effects based on static variable initialization, then we may be waiting for a long time that to happen.

Rational For beforeFieldInit

Why did CLI do this? The CLI specification claims that it is expensive to ensure that type initializers are run before a static method is called, particularly when executed from multiple application domains. CLI feels that this is OK most of the time. Let me examine this claim in some detail. In the code example above, say that f1() uses r1, and f2() does not use r1. If f2() is called, it doesn't reference r1 and hence, r1 is not initialized. As long as f2() doesn't depend on the initialization of r1 indirectly, this is OK. But what if in the process of instantiating r1, the constructor of Resource1() sets up a static hash table in some other class upon which f2() depends? As long as these side effects are not going on, then the facility of beforeFieldInit is fine.

In other words, if you need a system- or module-wide initialization, then use a different approach and don't depend on the side effects produced by static variable initialization. So initialization of a class should be a separate language construct, rather than being a side effect of field initialization. "Static constructor" is one such language construct with initialization semantics.

Base Classes Static Variables?

Before covering the static constructors it is worth noting that the CLI specification goes on to warn us about assumptions about base class type initialization. It tells us that don't expect any such initialization to happen automatically. To quote CLI: "Execution of any type's initializer method will not trigger automatic execution of any initializer methods defined by its base type, nor of any interfaces that the type implements."

Static Constructors to the Rescue, in a Couple of Ways

Let us modify the above class and initialize r1 through a static constructor instead. The resulting class will look like the following:


public class UtilityClass
{

  //Resources
  static Resource1 r1 = null;

  static UtilityClass()
  {
    r1 = new Resource1();
  }

  static void f1(){}
  static void f2(){}
}

There is an assurance in the language that this static constructor gets called before any other static method gets called. That means that it is guaranteed that the variables will be initialized before any static function is invoked on that class. Let us look at what the C# documentation says about static constructors:

  • Static constructors are not inherited, and cannot be called directly.
  • The exact timing of static constructor execution is implementation-dependent, but is subject to the following rules:
    • The static constructor for a class executes before any instance of the class is created.
    • The static constructor for a class executes before any of the static members for the class are referenced.
    • The static constructor for a class executes after the static field initializers (if any) for the class.
    • The static constructor for a class executes, at most, one time during a single program instantiation.
    • The order of execution between two static constructors of two different classes is not specified.

To further understand and elaborate on the above rules, let us consider the following class definition:


public class UtilityClass
{

  //Resources
  static Resource1 r1 = null;
  static Resource2 r2 = new Resource2();

  static UtilityClass()
  {
    r1 = new Resource1();
  }

  static void f1(){}
  static void f2(){}
}

Pages: 1, 2

Next Pagearrow