C# 静态只读字段初始值设定项与静态构造函数初始化

C# 静态只读字段初始值设定项与静态构造函数初始化,c#,c#-3.0,c#-2.0,initializer,static-constructor,C#,C# 3.0,C# 2.0,Initializer,Static Constructor,下面是初始化静态只读字段的两种不同方法。这两种方法之间有区别吗?如果是,什么时候应该选择其中一个 A类 { 私有静态只读字符串连接字符串= WebConfiguration Manager.ConnectionString[“SomeConnection”].ConnectionString; } B类 { 私有静态只读字符串连接字符串; 静态B() { 连接字符串= WebConfiguration Manager.ConnectionString[“SomeConnection”].Conn

下面是初始化静态只读字段的两种不同方法。这两种方法之间有区别吗?如果是,什么时候应该选择其中一个

A类
{
私有静态只读字符串连接字符串=
WebConfiguration Manager.ConnectionString[“SomeConnection”].ConnectionString;
}
B类
{
私有静态只读字符串连接字符串;
静态B()
{
连接字符串=
WebConfiguration Manager.ConnectionString[“SomeConnection”].ConnectionString;
}
}

它们本质上是相同的,但是如果碰巧对静态字段和静态类型构造函数都有只读赋值,则只读赋值首先发生。

这两者之间有一个细微的区别,这可以在IL代码中看到——放置一个显式静态构造函数告诉C#编译器不要将类型标记为。beforefieldinit会影响类型初始值设定项的运行时间,例如,在编写时了解这一点非常有用

简言之,区别在于:

.class private auto ansi beforefieldinit A
.class private auto ansi B
在所有其他方面,它们都是相同的。反射器输出:

A类:

.class private auto ansi beforefieldinit A
    extends [mscorlib]System.Object
{
    .method private hidebysig specialname rtspecialname static void .cctor() cil managed
    {
        .maxstack 8
        L_0000: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string, class Connection> WebConfigurationManager::ConnectionStrings
        L_0005: ldstr "SomeConnection"
        L_000a: callvirt instance !1 [mscorlib]System.Collections.Generic.Dictionary`2<string, class Connection>::get_Item(!0)
        L_000f: ldfld string Connection::ConnectionString
        L_0014: stsfld string A::connectionString
        L_0019: ret 
    }

    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: call instance void [mscorlib]System.Object::.ctor()
        L_0006: ret 
    }

    .field private static initonly string connectionString
} 
.class private auto ansi beforefieldinit A
扩展[mscorlib]System.Object
{
.method private hidebysing specialname rtspecialname static void.cctor()cil managed
{
.maxstack 8
L_0000:ldsfld类[mscorlib]系统.集合.泛型.字典`2网络配置管理器::连接字符串
L_0005:ldstr“SomeConnection”
L_000a:callvirt实例!1[mscorlib]System.Collections.Generic.Dictionary`2::get_项(!0)
L_000f:ldfld字符串连接::ConnectionString
L_0014:stsfld字符串A::connectionString
L_0019:ret
}
.method public hidebysing specialname rtspecialname实例void.ctor()cil托管
{
.maxstack 8
L_0000:ldarg.0
L_0001:调用实例void[mscorlib]System.Object::.ctor()
L_0006:ret
}
.field私有静态initonly字符串连接字符串
} 
B类:

.class private auto ansi B
    extends [mscorlib]System.Object
{
    .method private hidebysig specialname rtspecialname static void .cctor() cil managed
    {
        .maxstack 8
        L_0000: nop 
        L_0001: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string, class Connection> WebConfigurationManager::ConnectionStrings
        L_0006: ldstr "SomeConnection"
        L_000b: callvirt instance !1 [mscorlib]System.Collections.Generic.Dictionary`2<string, class Connection>::get_Item(!0)
        L_0010: ldfld string Connection::ConnectionString
        L_0015: stsfld string B::connectionString
        L_001a: ret 
}

    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: call instance void [mscorlib]System.Object::.ctor()
        L_0006: ret 
    }


    .field private static initonly string connectionString    
}
.class私有自动ansi B
扩展[mscorlib]System.Object
{
.method private hidebysing specialname rtspecialname static void.cctor()cil managed
{
.maxstack 8
L_0000:没有
L_0001:ldsfld类[mscorlib]系统.集合.通用.字典`2网络配置管理器::连接字符串
L_0006:ldstr“SomeConnection”
L_000b:callvirt实例!1[mscorlib]System.Collections.Generic.Dictionary`2::get_项(!0)
L_0010:ldfld字符串连接::ConnectionString
L_0015:stsfld字符串B::connectionString
L_001a:ret
}
.method public hidebysing specialname rtspecialname实例void.ctor()cil托管
{
.maxstack 8
L_0000:ldarg.0
L_0001:调用实例void[mscorlib]System.Object::.ctor()
L_0006:ret
}
.field私有静态initonly字符串连接字符串
}

beforefieldinit属性指示初始化是如何进行的

在显式静态构造函数初始化的情况下,静态成员的初始化在访问类型时发生。在A类情况下给出的示例中,初始化仅在第一次引用连接字符串时发生,而在B类情况下,初始化将在第一次引用类型类B时发生,不一定访问连接字符串


只有C#(.NET4.0)为我们提供了如何初始化静态成员的控制。在VB.NET中,只有非beforefieldinit方法是可能的,而在C++/CLI中,只有beforefieldinit机制是可能的。

我必须补充的是,如果存在显式构造函数(非beforefieldinit版本),访问静态成员的速度相对较慢

“在类A的例子中,初始化只会在第一次引用connectionString时发生”-我相信这可以概括为“初始化只会在第一次引用类A的任何静态字段时发生”