Creating a variable

  • A+
Category:Languages

I'm fairly new to c# and would like to know something about the following code:

void Method1() { string str =  client.GetString("http://msdn.microsoft.com");  } 

What exactly happens when the first line in Method1 is carried out? I understand memory is set aside for the string variable str, but does the RHS of the statement also get carried out at this stage? ie does it actually retrieve a value for the RHS? Thanks

EDIT: Thanks chaps, all settled now

 


This depends a lot on what you do next. There's a very good chance that the compiler will actually remove str completely if you don't use it (unless you use it in the next step, or the things you do between now and then are "net zero" in terms of stack positions). It will still execute the call to client.GetString(...), of course; the question is what does it do with the result? There's various ways the compiler can interpret this:

  • as a local:

stack space for the local is reserved as part of the stackframe entry; after the call to GetString the compiler emits stloc (or a variant)

  • as an ambient stack value

no explicit stack space is reserved for the local; after the GetString() it is simply left where it is for the next operation to consume (for example, this would be perfect if followed by a static call like Console.WriteLine(str);); it might also be cloned (dup) if needed multiple times

  • popped

no explicit stack space is reserved for the local; after the GetString() it is simply dropped (pop)

  • as a field

this would apply for iterator blocks and async methods; very complicated to explain

Ultimately, if you really want to know, you need to look at the real code, then look at the IL - ideally compiled in "release" mode.

You can see examples of some of these in this test code on sharplab.io

or copied here:

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); } 

becomes:

.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 

or as 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 

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: