I will not go into many details because various information pertinent to the subject has already been answered in other questions. I'm imagining that you understand the difference between static members and instance members .
The static constructor serves to initialize the static members of the class (as opposed to initializing the members of the instantiated object). And it is called exclusively by CLR at some point before some 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). There can only be one constructor without a parameter.
Since it is common for members to be initialized on their own, we rarely need to write them. But there may be some situations where the compiler can not evaluate the initialization expression, may need a specific boot order (one depends on the other), do something extra besides boot, then it can be useful.
Its utility is the same as an instance constructor (it can be seen in linked questions below), no more or less, it only changes the members it can manipulate.
Actually the compiler also generates a static constructor whenever there is some initialization of static members. Initialization can not occur magically, any code to be executed must always be within a method, in this case the static constructor.
public class Exemplo {
static int x = 1;
}
In the background something like this will be generated:
public class Exemplo {
static int x;
static Exemplo() { x = 1; }
}
IL code generated for the code of the question (note the existence of two ctor
, one normal and another instance and note 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
Avoid use
It is advisable to avoid use as much as possible especially if you want performance.
It is a danger to do something that generates an exception in a static constructor. Whoever called has to capture, right? It was not his code that called him, it was the virtual machine. Disaster in sight (class becomes invalid - not instances).
It looks like the static constructor, but it is not.
Actually in the query example what you are calling is not the static constructor, it is the parameterless instance constructor that the compiler generates for you ( default constructor ) so that the class can be instantiated in any situation. The instance constructor is for initializing instance members.
Difference between them
Basically it is what they manipulate and how they are called. But there are small differences, such as how you can define them, for example.
More information: