Click here to Skip to main content
15,891,704 members
Articles / Programming Languages / C#

Static constructors and way forward (.NET optimized Singleton pattern)

Rate me:
Please Sign up or sign in to vote.
3.81/5 (16 votes)
1 Mar 2009CPOL5 min read 45.5K   20   17
A simple guide to static constructors in C# and its uses in the >NET optimized Singleton pattern.

Introduction

A static constructor intelligent inclusion in C# .NET is used to initialize any static data, or to perform a particular action that needs to be performed only once.

Static constructors are declared using the following declaration syntax:

C#
static classname()
{
  //constructor body...
}

Static constructors are invoked automatically when one of the following happens:

  • When an instance of the class is created.
  • A static member (properties or methods) of the class is invoked.

Usage

There are cases where certain states of a library need to be initialized before using the library. Static constructors provide a clean way to solve the initialization problems in C# programs.

Normally, we do the initialization of states inside normal constructors. But, the problem with that is, the constructor is invoked upon instantiation of the class using the new keyword. When the class contains the utilities as static functions, a static constructor or a static field ensures the initialization of required states well before invoking the static method.

It is also assured that the static constructor for a class executes at most once in a given application domain. So, it also can be used to create a singleton instance of a class. There are performance issues with this approach, which will be discussed later in the article.

Resource initialization using inline instantiation of static objects

You may say, why not initialize static data members where we declare them in the code?

It’s quite possible that normal static field/resources can be initialized by using inline instantiation of static objects.

C#
public class StaticTest
{
   //Resources
   public static Resource1 rsr1 = new Resource1();
   public static void fun1(){}
   public static void fun2(){}
}

So, if fun1() or fun2() is to be called, there is an assumption that "rsr1" should have been initialized by then. So, static data members can certainly be initialized at the time of their declaration, but there are times when the value of one static member may depend upon the value of another static member.

For example: If the class is marked as beforeFieldInit, then the resource 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 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 for that to happen.

In such cases, we definitely need some mechanism to handle conditional initialization of static members. To handle such situations, C# provides a static constructor.

The simple solution to the complicated problems is the static constructor

C#
public class StaticTest 
{
    //Resources 
    public static Resource1 rsr1 = null; 
    static StaticTest() 
    {
        rsr1 = new Resource1(); 
    }
    public static void fun1(){} 
    public static void fun2(){} 
}

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.

Some important points regarding static constructors, from the C# Language Specification

  • 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 initializes (if any) for the class.
  • The static constructor for a class executes at most once during a single program instantiation.
  • A static constructor does not take access modifiers or have parameters.
  • A static constructor is called automatically to initialize the class before the first instance is created or any static members are referenced.
  • A static constructor cannot be called directly.
  • The user has no control on when the static constructor is executed in the program.
  • A typical use of static constructors is when the class is using a log file and the constructor is used to write entries to this file.

Singleton using static constructors

The implementation of a singleton in C# using a static constructor is quite simple. It is thread safe and lazy.

C#
public sealed class Singleton 
{ 
    static readonly Singleton instance=new Singleton(); 
    // Explicit static constructor to tell C# compiler 
    // not to mark type as beforefieldinit 
    static Singleton() 
    { 
    } 
    Singleton()
    {
    }
    public static Singleton Instance 
    {
        get 
        { 
            return instance; 
        } 
    }
}

This implementation is quite simple. It could be made even simple by making the instance a public static readonly variable. However, the only time I would normally go away from it is if I needed to be able to call other static methods without triggering initialization, or if I needed to know whether or not the singleton has already been instantiated. Here is the solution to the above problems.

C#
public sealed class Singleton {
    Singleton() 
    { 
    } 
    public static Singleton Instance 
    { 
        get 
        { 
            return Nested.instance; 
        } 
    } 
    class Nested 
    { 
        // Explicit static constructor to tell C# compiler 
        // not to mark type as beforefieldinit 
        static Nested() 
        { 
        } 
        internal static readonly Singleton instance = new Singleton(); 
    } 
}

Here, instantiation is triggered by the first reference to the static member of the nested class, which only occurs in Instance. This means the implementation is fully lazy, but has all the performance benefits of the previous ones. Note that although nested classes have access to the enclosing class' private members, the reverse is not true, hence the need for instance to be internal here. That doesn't raise any other problems, though, as the class itself is private. The code is a bit more complicated in order to make the instantiation lazy, however.

Generic singleton pattern

The below example shows the >NET optimized generic Singleton class. This example can be a bit modified to create a generic singleton factory. This is a thread safe and lazy implementation with the added flavors of Generics.

C#
public static class Singleton<T> where T : new() 
{ 
    public static T Instance 
    { 
        get 
        { 
            return SingletonInternal.instance; 
        } 
    } 
    private class SingletonInternal 
    { 
        static SingletonInternal() 
        { 
        } 
        internal static readonly T instance = new T(); 
    } 
}

Conclusion

The static constructor is a simple but important concept in the C# language. It is used for initialization of states and resources.

I dedicate this article to my friend Rajesh Ganta.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
India India
I am a software developer,currently developing softwares in C# .Net.I believe there is no shortcut to success and your ability to learn faster than your competition is your only sustainable competitive advantage.

Comments and Discussions

 
GeneralGood one Pin
jug.shon5-Mar-09 17:59
jug.shon5-Mar-09 17:59 
GeneralMy Vote of 5.......Nice article Pin
robert.beck15-Mar-09 17:27
robert.beck15-Mar-09 17:27 
GeneralGood for the static constructors Pin
User 43300283-Mar-09 0:38
User 43300283-Mar-09 0:38 
GeneralNice atricle ...vote of 5 Pin
chon_1112-Mar-09 22:29
chon_1112-Mar-09 22:29 
GeneralMy vote of 1 Pin
azweepay2-Mar-09 21:01
azweepay2-Mar-09 21:01 
GeneralRe: No its a good article.. Pin
chon_1112-Mar-09 22:25
chon_1112-Mar-09 22:25 
GeneralMy vote of 1 Pin
frogsnot9812-Mar-09 19:15
frogsnot9812-Mar-09 19:15 
GeneralGood Stuff Dude Pin
pat12452-Mar-09 16:25
pat12452-Mar-09 16:25 
GeneralUseful information Pin
chon_1112-Mar-09 16:16
chon_1112-Mar-09 16:16 
GeneralGood article ....nice stuff Pin
RamKishorDash2-Mar-09 4:29
RamKishorDash2-Mar-09 4:29 
GeneralMy vote of 1 Pin
wegenerb1-Mar-09 11:06
wegenerb1-Mar-09 11:06 
GeneralRe: My vote of 1 Pin
ptmcomp3-Mar-09 8:45
ptmcomp3-Mar-09 8:45 
GeneralMy vote of 2 Pin
Omer Mor1-Mar-09 7:11
Omer Mor1-Mar-09 7:11 
Trivial, and contains information that was already written lots of places elsewhere.
GeneralMeh Pin
PIEBALDconsult1-Mar-09 4:11
mvePIEBALDconsult1-Mar-09 4:11 
GeneralRe: Meh Pin
wegenerb1-Mar-09 11:07
wegenerb1-Mar-09 11:07 
GeneralRe: Meh Pin
PIEBALDconsult1-Mar-09 14:50
mvePIEBALDconsult1-Mar-09 14:50 
GeneralRe: Meh Pin
Bhagaban11-Mar-09 23:08
Bhagaban11-Mar-09 23:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.