C# Snippet Tutorial - Static Constructors

Skill

C# Snippet Tutorial - Static Constructors

Posted in:

I'm going to guess that pretty much everyone who reads this blog knows about constructors and how they work. And I bet everyone knows about static variables and functions as well. But did you know that there is such a thing as a static constructor in C#? Yup, a static constructor. And that's what we are going to take a look at today.

The concept behind them is actually pretty simple. A static constructor in C# is a chunk of code that is executed right after all the static variables for a class are initialized. You declare it similar to the way you declare a regular constructor (except that it is declared static). So in many ways, they act exactly like a class constructor, except for statics. Don't worry, if that didn't make perfect sense, there are plenty of examples to come.

Lets take a look at a really simple class with a static constructor:

public class StaticTest
{
  public static int SomeVarA;

  static StaticTest()
  {
    SomeVarA = 1;
  }
}

Granted, that is a pretty silly constructor, since I could have initialized SomeVarA right up in the field declaration. But it gets the point across. The static constructor has to follow all the rules of a normal static function, i.e., no this keyword and things like that. In addition, it doesn't have a private/public/protected modifier. This is because those modifiers don't make sense in this context - no one can ever directly call this function. Also, it can't take any arguments - again, because no one ever actually directly calls this function.

If no one ever directly calls this function, when does it actually get run? Well, that is a good question. Essentially, the first time someone touches the class, by creating an instance, or by touching some static variable or function, the static constructor gets run. We can actually see this in action:

public class Program
{
  static void Main(string[] args)
  {
    Debug.WriteLine("Start Time: " + Environment.TickCount);
    Debug.WriteLine("StaticTest Static Field At: " + StaticTest.AFieldToAccess);
  }
}

public class StaticTest
{
  public static long AFieldToAccess = Environment.TickCount;

  static StaticTest()
  {
    Debug.WriteLine("StaticTest Static Constructor At: " + Environment.TickCount);
  }
}

Running this code produces the following output (or something similar, depending on your current computer time):

Start Time: 167393939
StaticTest Static Constructor At: 167393959
StaticTest Static Field At: 167393959

So we hit the start time first, as expected, and then because we are hitting on the StaticTest class for the first time (we are trying to access AFieldToAccess), the static constructor runs.

Creating an instance of StaticTest would have the same affect:

public class Program
{
  static void Main(string[] args)
  {
    Debug.WriteLine("Start Time: " + Environment.TickCount);
    new StaticTest();
    new StaticTest();
    new StaticTest();
  }
}

public class StaticTest
{
  public static long AFieldToAccess = Environment.TickCount;

  static StaticTest()
  {
    Debug.WriteLine("StaticTest Static Constructor At: " + Environment.TickCount);
  }

  public StaticTest()
  {
    Debug.WriteLine("StaticTest Regular Constructor At: " + Environment.TickCount);
  }
}

This produces the output:

Start Time: 167855613
StaticTest Static Constructor At: 167855633
StaticTest Regular Constructor At: 167855633
StaticTest Regular Constructor At: 167855633
StaticTest Regular Constructor At: 167855633

As expected, the static constructor runs only once, right before any of the StaticTest objects get instantiated.

So What happens if StaticTest is never referred to? Well, the static constructor never gets run:

public class Program
{
  static void Main(string[] args)
  {
    Debug.WriteLine("Start Time: " + Environment.TickCount);
  }
}

public class StaticTest
{
  public static long AFieldToAccess = Environment.TickCount;

  static StaticTest()
  {
    Debug.WriteLine("StaticTest Static Constructor At: " + Environment.TickCount);
  }
}

In this case, the only output is:

Start Time: 168189944

This shows that static constructors don't 'just run' - they are only triggered when code touches a class for the first time.

What are static constructors useful for? They have come in handy every once in a while when I have needed to initialize some static fields in a complex way. For example, say you have a static class that the rest of your code uses to do database access. A static constructor is a handy place to initialize that database connection, because it means that the connection will get created right before it is first needed. There are plenty of other uses for them as well - that just happens to be the fist one that popped into my head.

That is it for this short primer on static constructors C#. If you have any questions on what I've discussed here, or anything else to do with static constructors, feel free to leave a comment below.

Davidq
12/04/2007 - 13:43

hey, interesting post. i'm not a c# developer but just outta curiosity, will this function trigger when casting?

reply

The Tallest
12/04/2007 - 17:42

Yup, casting will trigger this as well. As far as I know, there is no way to get an instance of a class without its static constructor running first.

reply

Pieter Breed
12/07/2007 - 02:29

Well, there is one instance that I know of when it won't run.

If you have a normal (ie, nonstatic) class, that inherits from a Parent class, and you call a static method on the Parent class, through your class, your class' static ctor won't run.

reply

The Tallest
12/07/2007 - 07:58

Nope, if you called the static method on the parent class "through your class", the static constructor on your class will run (if it hasn't already run). The "through your class" part is key - it is when the class is touched for the very first time that the static constructor runs. If you didn't touch the child class - say you were calling the parent static method from some other spot in your code that did not involve your child class in any way - the child class constructor won't run. But it makes sense in that case that it wouldn't run - you didn't actually touch the child class.

reply

Anonymous
05/22/2008 - 17:32

You say "Nope, if you called the static method on the parent class “through your class”, the static constructor on your class will run (if it hasn’t already run)."

Unfortunately, not true. I just got bit by this one. The compiler optimizes a static method call--it compiles it down to a call on the exact method, since this is known at compile time, so there's no such thing as really calling "through your class". Robert Chipperfield has a little writeup on this surprise at http://www.simple-talk.com/community/blogs/robertchipperfield/archive/2007/08/03/34359.aspx.

reply

Mg
12/13/2007 - 07:42

There is another issue regarding static constructors - they prevent from marking your class with beforefieldinit.
Basically this mark on the class means that the moment of static field initialization is undefined.

You can find an interesting article about this here:
http://www.yoda.arachsys.com/csharp/beforefieldinit.html

reply

The Fattest
12/13/2007 - 10:43

mg, nice comment. That article is very interesting. Although I think that in most cases this is not going to be an issue. Do you know who the author of the article was I either missed it or it didn't have it.

reply

Mg
12/13/2007 - 17:20

The author is Jon Skeet, he wrote several other interesting articles on C# on his web page:
http://www.yoda.arachsys.com/

Don't miss this article on singletons, it has some examples of using static constructors: http://www.yoda.arachsys.com/csharp/singleton.html

reply

Junayed
12/14/2008 - 13:15

nice tutorial!
please give us a real-time small example to understand static constructor purpose more clearly if possible.

_Junayed

reply

lazy
01/10/2010 - 05:37

thanks for information nice

http://csharptalk.com

lazy

reply

Add Comment

Put code snippets inside language tags:
[language] [/language]

Examples:
[javascript] [/javascript]
[actionscript] [/actionscript]
[csharp] [/csharp]

See here for supported languages.

Javascript must be enabled to submit anonymous comments - or you can login.

Sponsors