支持字段的自动初始化
Automatic initialization of backing fields
这个问题不是关于如何初始化支持字段...
让我们假设这个 class:
public class Test
{
public int PropertyA { get; set; }
public int PropertyB { get; set; }
private int _propertyC;
public int PropertyC { get { return _propertyC; } set { _propertyC = value; } }
}
定义了许多属性,自动和显式实现。
让我们仔细看看 PropertyA
是如何编译的(64 位调试)。 MSIL 输出是这样的:
.field private int32 '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 )
.property instance int32 PropertyA()
{
.get instance int32 TestCode.Test::get_PropertyA()
.set instance void TestCode.Test::set_PropertyA(int32)
} // end of property Test::PropertyA
.method public hidebysig specialname instance int32
get_PropertyA() cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld int32 TestCode.Test::'k__BackingField'
IL_0006: ret
} // end of method Test::get_PropertyA
.method public hidebysig specialname instance void
set_PropertyA(int32 'value') cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld int32 TestCode.Test::'k__BackingField'
IL_0007: ret
} // end of method Test::set_PropertyA
这是非常基本的,它定义了支持字段、属性,然后是 get_
和 _set
加载或设置支持的 属性 方法场.
我不明白的是(直到现在我都认为这是理所当然的),这是一个完全合法的构造函数:
public Test()
{
Debug.WriteLine($"{PropertyA.ToString()}");
Debug.WriteLine($"{_propertyC.ToString()}");
}
虽然这显然是一个编译器错误:
public Test()
{
int i;
Debug.WriteLine($"{i.ToString()}");
}
正如预期的那样,给出了 CS0165 "Use of unassigned local variable 'i'"。在为此做一些研究并挖掘 ECMA Spec, and the Microsoft C# spec(5.0 是最后一个正式文件,6.0 似乎松散地分布在 Roslyn 项目中),我找不到任何与字段初始化相关的内容。
我确实发现 this reference from VS2003 避开了 class 字段被初始化为类型的 default
值,但这表明这是语言的一部分而不是运行时.
所以问题是...运行时是否执行字段的初始化,或者我是否在初始化这些值的编译器的 MSIL 中遗漏了某些内容?我假设编译器会这样做,否则我希望两个示例构造函数中的 CS0165 相同。
Does the runtime perform the initialization of the fields, or am I missing something in the MSIL from the compiler that is initializing these values?
规范的 §5.2 和 §5.3 部分分别讨论了默认值和明确赋值。
引自规范 (§5.2):
Initialization to default values is typically done by having the memory manager or garbage collector initialize memory to all-bits-zero before it is allocated for use. For this reason, it is convenient to use all-bits-zero to represent the null reference.
这继续显示内存管理器和 GC 负责默认值初始化。
这个问题不是关于如何初始化支持字段...
让我们假设这个 class:
public class Test
{
public int PropertyA { get; set; }
public int PropertyB { get; set; }
private int _propertyC;
public int PropertyC { get { return _propertyC; } set { _propertyC = value; } }
}
定义了许多属性,自动和显式实现。
让我们仔细看看 PropertyA
是如何编译的(64 位调试)。 MSIL 输出是这样的:
.field private int32 '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 ) .property instance int32 PropertyA() { .get instance int32 TestCode.Test::get_PropertyA() .set instance void TestCode.Test::set_PropertyA(int32) } // end of property Test::PropertyA .method public hidebysig specialname instance int32 get_PropertyA() cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld int32 TestCode.Test::'k__BackingField' IL_0006: ret } // end of method Test::get_PropertyA .method public hidebysig specialname instance void set_PropertyA(int32 'value') cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Code size 8 (0x8) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldarg.1 IL_0002: stfld int32 TestCode.Test::'k__BackingField' IL_0007: ret } // end of method Test::set_PropertyA
这是非常基本的,它定义了支持字段、属性,然后是 get_
和 _set
加载或设置支持的 属性 方法场.
我不明白的是(直到现在我都认为这是理所当然的),这是一个完全合法的构造函数:
public Test()
{
Debug.WriteLine($"{PropertyA.ToString()}");
Debug.WriteLine($"{_propertyC.ToString()}");
}
虽然这显然是一个编译器错误:
public Test()
{
int i;
Debug.WriteLine($"{i.ToString()}");
}
正如预期的那样,给出了 CS0165 "Use of unassigned local variable 'i'"。在为此做一些研究并挖掘 ECMA Spec, and the Microsoft C# spec(5.0 是最后一个正式文件,6.0 似乎松散地分布在 Roslyn 项目中),我找不到任何与字段初始化相关的内容。
我确实发现 this reference from VS2003 避开了 class 字段被初始化为类型的 default
值,但这表明这是语言的一部分而不是运行时.
所以问题是...运行时是否执行字段的初始化,或者我是否在初始化这些值的编译器的 MSIL 中遗漏了某些内容?我假设编译器会这样做,否则我希望两个示例构造函数中的 CS0165 相同。
Does the runtime perform the initialization of the fields, or am I missing something in the MSIL from the compiler that is initializing these values?
规范的 §5.2 和 §5.3 部分分别讨论了默认值和明确赋值。
引自规范 (§5.2):
Initialization to default values is typically done by having the memory manager or garbage collector initialize memory to all-bits-zero before it is allocated for use. For this reason, it is convenient to use all-bits-zero to represent the null reference.
这继续显示内存管理器和 GC 负责默认值初始化。