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 right-hand side of the statement also get carried out at this stage? i.e. does it actually retrieve a value for the right-hand side?
The 5-year variable mortgage is Canada's most popular variable-rate mortgage. It is called a variable-rate mortgage because the rate is based on a lender's Prime rate, and can go up or down throughout the 5 years of the mortgage.
This mortgage interest rate fluctuates with the prime rate while payments remain the same. If prime goes down, more of your monthly payment is applied to the principle balance of the mortgage. If prime increases, more goes to the interest.
Variable-rate mortgages can be open or closed. The main differences between closed and open variable-rate mortgages are cost and flexibility. With an open mortgage, you can make additional mortgage payments without the fear of a prepayment penalty, but you pay for this flexibility with a higher interest rate.
An open mortgage is one with flexible options to increase your mortgage repayments, either by increasing your regular payments or via a lump sum. A closed mortgage, on the other hand, will penalize you for paying off all or part of your mortgage early.
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:
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)
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
no explicit stack space is reserved for the local; after the GetString()
it is simply dropped (pop
)
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With