编译器和运行时都不需要保证超出范围的本地变量实际上会截断其内容的生命周期。出于计算生命周期的目的,编译器或运行时将其视为大括号不存在是完全合法的。如果您需要基于大括号的清理,则实现 IDisposable 并使用“使用”块。
更新:
关于您的问题“为什么在优化和未优化的构建中会有不同”,那么,看看 codegen 的区别。
未优化:
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 28 (0x1c)
.maxstack 1
.locals init (class test.Foo V_0)
IL_0000: nop
IL_0001: nop
IL_0002: newobj instance void test.Foo::.ctor()
IL_0007: stloc.0
IL_0008: nop
IL_0009: call void [mscorlib]System.GC::Collect()
IL_000e: nop
IL_000f: call void [mscorlib]System.GC::WaitForPendingFinalizers()
IL_0014: nop
IL_0015: call string [mscorlib]System.Console::ReadLine()
IL_001a: pop
IL_001b: ret
} // end of method Program::Main
优化:
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 23 (0x17)
.maxstack 8
IL_0000: newobj instance void test.Foo::.ctor()
IL_0005: pop
IL_0006: call void [mscorlib]System.GC::Collect()
IL_000b: call void [mscorlib]System.GC::WaitForPendingFinalizers()
IL_0010: call string [mscorlib]System.Console::ReadLine()
IL_0015: pop
IL_0016: ret
} // end of method Program::Main
显然差别很大。显然,在未优化的构建中,引用存储在本地插槽零中,并且在方法结束之前永远不会被删除。因此,在方法结束之前,GC 无法回收内存。在优化的构建中,引用存储在堆栈中,立即从堆栈中弹出,并且 GC 可以自由回收它,因为堆栈上没有剩余的有效引用。