在调用方法并将返回值赋给数组时,为什么C#在调用方法时使用数组引用?

时间:2018-05-08 15:48:54

标签: c# arrays methods return-value

我有以下C#程序:

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

Get()调用Main()后,我希望foo数组在第一个位置包含5。但是,它是零。为什么会这样?

就像C#在调用foo方法时捕获对Get()的引用。 然后,此旧数组引用用于分配Get()返回值(而不是在Get()中实例化的新值)。

1 个答案:

答案 0 :(得分:5)

语句中的操作数始终从左到右计算,即使运算符的优先规则决定事情如何处理会导致复杂的逻辑。这意味着foo[0]目标实际上是在<{>}之前之前执行。你可以在IL中看到这个:

Get

请注意,.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 ldsfld ... foo(常数为零)在ldc.i4.0 之前执行,这些值留在堆栈上以供在稍后call ... Get()。在更复杂的情况下(涉及括号等),看到编译器用于保留从左到右评估的技巧可能会非常有趣。像sharplab这样的工具可以帮助解决这个问题。 here's your example in sharplab

这是由于ECMA 334规范中的12.4运算符:

  

12.4.1一般

     

...

     

表达式中运算符的求值顺序取决于运算符的优先级和关联性(第12.4.2节)。

     

表达式中的操作数从左到右进行计算。 [例如:在F(i)+ G(i ++)* H(i)中,使用旧的i值调用方法F,然后使用旧值i调用方法G,并且最后,使用i的新值调用方法H.这与运算符优先级分开并且与运算符优先级无关。 结束示例]