What is the purpose of a static constructor?

Asked

Viewed 1,287 times

15

I’ve always used builders as follows:

public MinhaClasse()
{
  //Algo
  ...
}

However I found that in C# it is possible to create a static constructor as follows:

public class MinhaClasse
{
    public string Propriedade { get; set; }

    static MinhaClasse() 
    {
        //Algo
        ....
    }
}

And the class with the static constructor is instantiated in the same way as a common class:

MinhaClasse c = new MinhaClasse();
c.Propriedade = "Hello Stackoverflow";
WriteLine(c.Propriedade);

Exit:

Hello Stackoverflow


Doubts

What is the purpose of a static constructor and what are the differences of the static constructor compared to the standard constructor?

  • Is there this static constructor? Wow, this is new for me. hehe

  • @diegofm tried in Java but it didn’t work it says q is invalid, however in C# it works hehe

  • why I was unaware, it is a serious problem that we stay closed to a language just saw. :/

  • http://stackoverflow.com/questions/4506990/what-is-the-use-of-static-constructors

  • There’s a Java too, there’s a link in my answer that speaks of this

2 answers

8

A static constructor in C# can never be called directly through code (in case your application has created a non-static constructor implicit by the compiler).

The static constructor is called before the first use of the class, whether it is a static call or through object to this class.

The main purpose of this type of constructor is to automatically initialize static members, considering for example that it is necessary to call a specific method to initialize a static property of this class this could be done manually (chance of the programmer forgetting to do it and corrupting the class) or by invoking the static constructor by the application automatically when the static call to this class is invoked (specifically before the call).

Complementing also, as the other answers put: The static constructor cannot contain parameters and cannot be manually invoked by the class user, so it will also not be impacted by public, protected and private modifiers.

8


I will not go into too much detail because various pertinent information to the subject has already been answered in other questions. I’m guessing you understand the difference between static and panel members.

The static constructor serves to initialize the static members of the class (as opposed to initializing the members of the instantiated object). And he’s called exclusively by CLR at some point before any static member is used, following rules set out in the specification (if all goes well it will only be called once and there is no way to control your call). Only one constructor can exist without parameter.

As it is common that members are already initialized on their own we rarely need to write them. But there may be some situations that the compiler fails to evaluate the initialization expression, may need a specific initialization order (one depends on the other), do something extra besides initialization, then it may be useful.

Its utility is the same as an instance constructor (can be seen in questions linked below), neither more nor less, only changes the members he can manipulate.

In fact the compiler also generates a static constructor whenever there is some initialization of static members. Initialization cannot occur magically, any code to be executed must always be inside a method, in case the static constructor.

public class Exemplo {
    static int x = 1;
}

In the background will be generated something like this:

public class Exemplo {
    static int x;
    static Exemplo() { x = 1; }
}

IL code generated for the question code (note the existence of two ctor, a normal and another instance and note the beforefieldinit ):

.class private auto ansi '<Module>'
{
} // end of class <Module>

.class public auto ansi beforefieldinit Program
    extends [mscorlib]System.Object
{
    // Methods
    .method public hidebysig static 
        void Main () cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 32 (0x20)
        .maxstack 2
        .locals init (
            [0] class MinhaClasse
        )

        IL_0000: nop
        IL_0001: newobj instance void MinhaClasse::.ctor() //   <========= note a chamada ao método de instância
        IL_0006: stloc.0
        IL_0007: ldloc.0
        IL_0008: ldstr "Hello Stackoverflow"
        IL_000d: callvirt instance void MinhaClasse::set_Propriedade(string)
        IL_0012: nop
        IL_0013: ldloc.0
        IL_0014: callvirt instance string MinhaClasse::get_Propriedade()
        IL_0019: call void [mscorlib]System.Console::WriteLine(string)
        IL_001e: nop
        IL_001f: ret
    } // end of method Program::Main

    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x207c
        // Code size 8 (0x8)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        IL_0006: nop
        IL_0007: ret
    } // end of method Program::.ctor

} // end of class Program

.class public auto ansi MinhaClasse
    extends [mscorlib]System.Object
{
    // Fields
    .field private string '<Propriedade>k__BackingField'
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
        01 00 00 00
    )
    .custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = (
        01 00 00 00 00 00 00 00
    )

    // Methods
    .method public hidebysig specialname 
        instance string get_Propriedade () cil managed 
    {
        .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
            01 00 00 00
        )
        // Method begins at RVA 0x2085
        // Code size 7 (0x7)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: ldfld string MinhaClasse::'<Propriedade>k__BackingField'
        IL_0006: ret
    } // end of method MinhaClasse::get_Propriedade

    .method public hidebysig specialname 
        instance void set_Propriedade (
            string 'value'
        ) cil managed 
    {
        .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
            01 00 00 00
        )
        // Method begins at RVA 0x208d
        // Code size 8 (0x8)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: ldarg.1
        IL_0002: stfld string MinhaClasse::'<Propriedade>k__BackingField'
        IL_0007: ret
    } // end of method MinhaClasse::set_Propriedade

    .method private hidebysig specialname rtspecialname static  
        void .cctor () cil managed   //<============== construtor estático aqui
    {
        // Method begins at RVA 0x2096
        // Code size 2 (0x2)
        .maxstack 8

        IL_0000: nop
        IL_0001: ret
    } // end of method MinhaClasse::.cctor

    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed   //<============== construtor de instância aqui
    {
        // Method begins at RVA 0x207c
        // Code size 8 (0x8)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        IL_0006: nop
        IL_0007: ret
    } // end of method MinhaClasse::.ctor

    // Properties
    .property instance string Propriedade()
    {
        .get instance string MinhaClasse::get_Propriedade()
        .set instance void MinhaClasse::set_Propriedade(string)
    }

} // end of class MinhaClasse

I put in the Github for future reference.

Avoid use

It is recommended to avoid use as much as possible mainly if you want performance.

It’s a danger to do something that generates an exception in a static constructor. Whoever called it has to capture it, right? It wasn’t your code that called it, it was the virtual machine. Disaster in sight (the class is in invalid state - not the instances).

In modern versions of C# [it is possible to control the moment of startup;'ao to avoid surprises.

It looks like the static constructor, but it’s not.

Actually in the example of using the question what you are calling is not the static constructor, it is the parameter-less instance constructor that the compiler generates for you (default constructor) so that the class can be instantiated in any situation. The instance constructor serves to initialize the instance members.

Difference between them

Basically it’s what they manipulate and what they’re called. But there are small differences, like the way you can define them, for example.

More information:

  • 3

    I was going to make an extra comment, but I think it would create confusion: in the background we can see the instance builder as a static method that generates an instance.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.