ONDotNet.com    
 Published on ONDotNet.com (http://www.ondotnet.com/)
 See this if you're having trouble printing code examples


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:

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(){}
}

Static Constructor Presence Trumps beforeFieldInit

Interestingly enough, according to the rules resource, r2 gets initialized first, before the static constructor is called and r1 is initialized. Even if r2 is never needed, it will still be initialized first. Defining a static constructor seems to "trump" the beforeFieldInit. So even if you have an empty static constructor, it is guaranteed that static variables will be initialized before any static function gets invoked.

If there is no static constructor, then the following rule taken from the C# documentation applies to the initialization of static variables:

"The static field variable initializers of a class correspond to a sequence of assignments that are executed at an implementation-dependent time prior to the static constructor for the class (if any) and prior to the first use of a static field of that class. The static field variable initializers are executed in the textual order in which they appear in the class declaration."

Summarizing the Usage of Static Constructors

It is one thing to open an Oxford English Language dictionary and learn a new word, and completely another thing before the word becomes part of the usage on a daily basis. Programming constructs are no different. These constructs need to be internalized before one can effectively use them. This is how I intend to internalize the static constructors:

When Is It OK Not to Use Static Constructors?

If all of your static variables can be set up by simply instantiating classes against them, then there is a good chance that you don't need a static constructor. What you have to watch out for, though, is that none of the constructors of these classes have side effects; for example, a class1 constructor doing something useful for a class2 constructor, or the usage of a class2 instance. In such a case, if a class2 variable is to be utilized first, then there is no guarantee that a class1 constructor would have run. Surprisingly, even this won't be a problem if these instances are the static instances of the same class; as soon as one of the class instances is utilized, everything in that class is initialized.

When to Use Static Constructors

If a class has a set of static variables that are mainly simple types and not functional classes, then these simple types need to be initialized procedurally, as opposed to instantiating them. For example, I consider ints, strings, etc., as simple types (although they are classes in their own right). A logging class needs to remember its log filename, log message levels etc., at start up. Assuming this log class is implemented as a static class, a static constructor will initialize these variables. If you want to do this using static variable initialization, then you need to have a class called LogInitialization, whose sole purpose is to initialize this static instance.

Singletons and Static Constructors


public class MySingletonClass
{
  public static MySingletonClass self = new MySingletonClass();
  //Nonstatic MySIngletonClass implementation follow
}

//singletonusage

MySingletonClass.self.doSomething();

The above example shows that the majority of singletons don't require static initializers.

An Alternative to Static Classes

There is no such language construct called a static class. I tend to refer to a class as a static class when much of its functionality is exposed as a collection of static functions. Often, these classes give rise to static constructors. It is possible to convert a static class to a regular class and use a singleton of this type, instead of the static class with which we have started. There are pros and cons to both approaches. First, let me show examples of both usages.

The Static Example Revisited



//Class definition

public class UtilityClass
{

  //Resources
  static Resource1 r1 = null;

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

//Let us see how the above class is used

UtilityClass.f1();
UtilityClass.f2();

In this scenario, programmers will directly call the static functions as if they are C-like functions. This approach has a lot of simplicity and as a result, is usually preferred for utility functions. On the negative side of this approach lies the first assertion that this is not object-oriented programming. If it gets the job done, and programmers use it without major drawbacks, this is quite reasonable.

Static Classes as Singletons

Let me rewrite the above class as a singleton and show how programmers can use such a facility.



//Class definition

public class SingletonUtilityClass
{
  public static SingletonUtilityClass self = new SingletonUtilityClass();

  //Resources
  Resource1 r1 = null;

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

//Let us see how the above class is used

SingletonUtilityClass.self.f1();
SingletonUtilityClass.self.f2();

Notice now that the class is a non-static, regular class. The only static variable is the "self" variable pointing to an instance of itself. This is a little bit more verbose than the static version of it. In addition to that you have to ensure the singleton semantics of it. You should ensure that the constructor of this is private and is not allowed to instantiate from anywhere, etc.

There is a reward for going this extra step. In the above example, the class is statically bound to the program. If you can utilize a factory that can dynamically instantiate classes and also permits the multiplicity of their instantiations, then you can take the above class and makes it a strategy/factory pattern. Once this happens, you can then change your implementation of methods at run time. When properly expanded, this method forms the basis of remoting, COM+, etc.

References

Satya Komatineni is the CTO at Indent, Inc. and the author of Aspire, an open source web development RAD tool for J2EE/XML.


Return to ONDotnet.com

Copyright © 2009 O'Reilly Media, Inc.