简体   繁体   中英

When calling a method and assigning returned value to an array, why is C# using the array reference when method was called?

I have the following C# program :

class Program
{ 
    static int[] foo = new int[1];

    static void Main()
    {
        foo[0] = Get();
        Console.WriteLine(foo[0]); //print "0"
    }

    static int Get()
    {
        foo = new int[1];
        return 5;
    }
}

After Get() has been called from Main() , I expect foo array to contains 5 at first position. However, it is zero. Why is it so ?

It is like C# captures a reference to foo when Get() method is called. This old array reference is then used for assigning Get() returned value (and not the new one instantiated in Get() ).

The operands in statements are always evaluated left to right, even if precedence rules for the operators deciding how things are then processed result in complex logic. This means that the foo[0] target is actually performed before the call to Get . You can see this in the IL:

.method private hidebysig static 
    void Main () cil managed 
{
    // Method begins at RVA 0x2050
    // Code size 25 (0x19)
    .maxstack 8

    IL_0000: ldsfld int32[] Program::foo
    IL_0005: ldc.i4.0
    IL_0006: call int32 Program::Get()
    IL_000b: stelem.i4
    IL_000c: ldsfld int32[] Program::foo
    IL_0011: ldc.i4.0
    IL_0012: ldelem.i4
    IL_0013: call void [mscorlib]System.Console::WriteLine(int32)
    IL_0018: ret
} // end of method Program::Main

Note that the ldsfld ... foo and ldc.i4.0 (the constant zero) are executed before the call ... Get() , with those values left on the stack for use in the later ldsfld ... foo . In more complicated cases (involving brackets etc), it can be very interesting to see the tricks the compiler has used to retain left-to-right evaluation. Tools like sharplab can help with this; here's your example in sharplab .

This is due to 12.4 Operators in the ECMA 334 specification:

12.4.1 General

...

The order of evaluation of operators in an expression is determined by the precedence and associativity of the operators (§12.4.2).

Operands in an expression are evaluated from left to right. [Example: In F(i) + G(i++) * H(i), method F is called using the old value of i, then method G is called with the old value of i, and, finally, method H is called with the new value of i. This is separate from and unrelated to operator precedence. end example]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM