9

First of all, I got an answer in What is the use of static constructors?, but I want an answer in this context.

Here is my C# static class:

public static class BasicClass
{
    static int i = 0;
    static BasicClass()
    {
        i = 10;
    }

    public static void Temp()
    {
        //some code
    }


    public static void Temp1()
    {
        //some code
    }
}

Inside this I have a static variable i which is initialized to 10 when it is first called. So basically it may be the purpose of a static constructor but the same thing can be achieved without declaring a static constructor by initializing the static int i = 10 which serves the same purpose that is gets initialized only once.

Then why do we need a static constructor? Or am I completely wrong in understanding the concept or use of static constructors?

Community
  • 1
  • 1
iJade
  • 23,144
  • 56
  • 154
  • 243
  • 2
    What if your program uses a config file? You'll want to store your config in static variables, but you'll have to read those from the file first, and if the file doesn't exist (or you can't open it for some other reasons), you'll want to set those configurations to their default values. That's what a static constructor **can** be used for. – Nolonar Mar 06 '13 at 14:47

8 Answers8

23

If you compile that class into an assembly, then use ILSpy or similar to disassemble the result, you will notice that all static member initialization is performed in the static constructor.

For instance, the following C# code:

public static class BasicClass
{
    static int i = 10;
}

Will produce IL equivalent to:

public static class BasicClass
{
    static int i;

    static BasicClass()
    {
        i = 10;
    }
}

In other words, direct initialization is only syntactic sugar provided by the C# compiler. Under the hood, a static constructor is still implemented.

Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
  • In that case, wouldn't it be enough if C# supported static member initialization (which would be actually compiled into a static constructor) but not actual static constructors? – svick Mar 06 '13 at 17:13
  • 1
    @svick, that would arguably be counter-productive. Sometimes you do have to perform operations less trivial than member initialization (e.g. simple loops and branches) globally for a class. Why remove support for a feature that is available in the CLR and only requires that a static constructor never throws? – Frédéric Hamidi Mar 06 '13 at 19:42
6

Well, in your example it is not indeed needed, but and imagine when i value has to be read from a database, text file, or any other resource? You might need something like:

static BasicClass()
{
    using (SomeConnection con = Provider.OpenConnection())
    {
        try
        {
            // Some code here
        }
        catch
        {
            // Handling expeptions, setting default value
            i = 10;
        }
    }
}

Now it is not possible to declare and initialize your static field, you're better served using a static constructor

RMalke
  • 4,048
  • 29
  • 42
1

You don't need a static constructor in this scenario.

static BasicClass()
{
    i = 10;
}

and

static int i = 10;

are functionally identical.

Roy Dictus
  • 32,551
  • 8
  • 60
  • 76
1

The answer is also in your linked question:

[...] useful in particular for reading required configuration data into readonly fields, etc.

It is run automatically by the runtime the first time it is needed (the exact rules there >are complicated (see "beforefieldinit"), and changed subtly between CLR2 and CLR4). >Unless you abuse reflection, it is guaranteed to run at most once (even if two threads >arrive at the same time).

You could initialize much more complicated things in a static constructor, like setting up a database connection and so on. If it would make sense is another thing...

Jobo
  • 1,084
  • 7
  • 14
1

An static contructor has sense if you need to execute some actions inside the constructor and you want a unique instance in the application. For example:

public static class BasicClass
{
    static MyConfiguration _myConfig;

    static BasicClass()
    {
       // read configuration from file
       _myConfig = ReadConfigFromConfigFile("somefile.conf");
    }

    private static MyConfiguration ReadConfigFromConfigFile(string file)
    {
       using (StreamReader reader = new StreamReader(file);
       {
         ...
       }
    }
}

In the scenario you explained, You don't need a static constructor explicitily.

Also, you can apply the singleton pattern to achieve this purpose.

Daniel Peñalba
  • 30,507
  • 32
  • 137
  • 219
  • 5
    It is dangerous to do this sort of thing in a static constructor. If the initialization throws an uncaught exception then there is no easy way to catch it, and the type then can *never* be loaded into that appdomain. – Eric Lippert Mar 06 '13 at 15:47
0

You can initialize fields in place only with compile time constants (your case). But in static constructor you can execute some code (e.g. read configuration file).

Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
0

A static constructor does not only the serve the purpose of intializing variables, but also create objects whicht might be necessary for your (static) class (or environment) to work and invoke methods on those objects or your class itself.

bash.d
  • 13,029
  • 3
  • 29
  • 42
0

One factor not yet mentioned is that there is a semantic difference between having a static constructor (written using constructor syntax) call foo() versus having a static field initializer do so. In particular, if a type has a static constructor written using constructor syntax, that constructor is guaranteed to be invoked the first time code which would "use" that type is executed; it will not be invoked before that, nor will it be invoked if the type isn't used. By contrast, although .NET guarantees that a type's static field initializers will run before any of its static fields are accessed, and will not run more than once, .NET is free to run such static initializers the first time it thinks a type might get used. Consider for example:

if (someCondition())
  for (i=0; i<100000000; i++)
    someClass.someStaticField++;

If when the Just-In-Time compiler encounters the above code, someClass has never been used, and it has a constructor declared using static constructor syntax, the resulting machine code will be something like:

if (someCondition())
  for (i=0; i<100000000; i++)
  {
    if (someClass.hasBeenInitialized)
      someClass.runConstructor();
    someClass.someStaticField++;
  }

performing the if-check within the loop. By contrast, if there had been field initializations but no constructor-style declaration, the JIT would likely perform the static construction of someClass before running the code, thus eliminating the need to include the if check within it.

supercat
  • 77,689
  • 9
  • 166
  • 211