这在很大程度上取决于您接下来要做什么。如果您不使用 str完全(除非您在下一步,或者你从现在到那时所做的事情就堆栈位置而言是“净零”)。当然,它仍然会执行对client.GetString(...) 的调用;问题是它对结果有什么作用?编译器可以通过多种方式解释它:
本地的堆栈空间作为堆栈帧条目的一部分保留;在调用GetString 之后,编译器会发出stloc(或变体)
没有为本地保留显式堆栈空间;在GetString() 之后,它只是留在原处以供下一个操作使用(例如,如果后面跟着Console.WriteLine(str); 之类的静态调用,这将是完美的);如果需要多次,它也可能被克隆 (dup)
没有为本地保留显式堆栈空间;在GetString() 之后,它被简单地删除了 (pop)
这适用于迭代器块和异步方法;解释起来很复杂
最终,如果你真的想知道,你需要看看真正的代码,然后看看IL——最好是在“发布”模式下编译。
您可以在this test code on sharplab.io 中查看其中一些示例
或复制到这里:
void Method1_Popped()
{
string str = client.GetString("http://msdn.microsoft.com");
}
void Method2_LeftOnStack()
{
string str = client.GetString("http://msdn.microsoft.com");
Console.WriteLine(str);
}
void Method3_Local()
{
string str = client.GetString("http://msdn.microsoft.com");
for(int i = 0;i < 3 ; i++) DoSomethingElse();
Console.WriteLine(str);
}
变成:
.method private hidebysig
instance void Method1_Popped () cil managed
{
// Method begins at RVA 0x2050
// Code size 18 (0x12)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld class SomeClient Foo::client
IL_0006: ldstr "http://msdn.microsoft.com"
IL_000b: callvirt instance string SomeClient::GetString(string)
IL_0010: pop
IL_0011: ret
} // end of method Foo::Method1_Popped
.method private hidebysig
instance void Method2_LeftOnStack () cil managed
{
// Method begins at RVA 0x2063
// Code size 22 (0x16)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld class SomeClient Foo::client
IL_0006: ldstr "http://msdn.microsoft.com"
IL_000b: callvirt instance string SomeClient::GetString(string)
IL_0010: call void [mscorlib]System.Console::WriteLine(string)
IL_0015: ret
} // end of method Foo::Method2_LeftOnStack
.method private hidebysig
instance void Method3_Local () cil managed
{
// Method begins at RVA 0x207c
// Code size 42 (0x2a)
.maxstack 2
.locals init (
[0] string,
[1] int32
)
IL_0000: ldarg.0
IL_0001: ldfld class SomeClient Foo::client
IL_0006: ldstr "http://msdn.microsoft.com"
IL_000b: callvirt instance string SomeClient::GetString(string)
IL_0010: stloc.0
IL_0011: ldc.i4.0
IL_0012: stloc.1
// sequence point: hidden
IL_0013: br.s IL_001f
// loop start (head: IL_001f)
IL_0015: ldarg.0
IL_0016: call instance void Foo::DoSomethingElse()
IL_001b: ldloc.1
IL_001c: ldc.i4.1
IL_001d: add
IL_001e: stloc.1
IL_001f: ldloc.1
IL_0020: ldc.i4.3
IL_0021: blt.s IL_0015
// end loop
IL_0023: ldloc.0
IL_0024: call void [mscorlib]System.Console::WriteLine(string)
IL_0029: ret
} // end of method Foo::Method3_Local
或作为 ASM:
Foo.Method1_Popped()
L0000: mov ecx, [ecx+0x4]
L0003: mov edx, [0xe42586c]
L0009: cmp [ecx], ecx
L000b: call dword [0x2ef71758]
L0011: ret
Foo.Method2_LeftOnStack()
L0000: push ebp
L0001: mov ebp, esp
L0003: mov ecx, [ecx+0x4]
L0006: mov edx, [0xe42586c]
L000c: cmp [ecx], ecx
L000e: call dword [0x2ef71758]
L0014: mov ecx, eax
L0016: call System.Console.WriteLine(System.String)
L001b: pop ebp
L001c: ret
Foo.Method3_Local()
L0000: push ebp
L0001: mov ebp, esp
L0003: mov ecx, [ecx+0x4]
L0006: mov edx, [0xe42586c]
L000c: cmp [ecx], ecx
L000e: call dword [0x2ef71758]
L0014: mov ecx, eax
L0016: call System.Console.WriteLine(System.String)
L001b: pop ebp
L001c: ret