При вызове метода и присвоении возвращаемого значения массиву, почему C # использует ссылку на массив при вызове метода? - PullRequest
0 голосов
/ 08 мая 2018

У меня есть следующая программа на 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 голосов
/ 08 мая 2018

Операнды * в операторах всегда оцениваются слева направо, даже если правила приоритета для операторов , определяющие, как все это затем обрабатывается , приводят к сложной логике. Это означает, что цель foo[0] фактически выполняется до вызова Get. Вы можете увидеть это в 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

Обратите внимание, что ldsfld ... foo и ldc.i4.0 (постоянный ноль) выполняются до call ... Get(), с этими значениями, оставленными в стеке для использования в более позднем ldsfld ... foo. В более сложных случаях (включая скобки и т. Д.) Может быть очень интересно увидеть приемы, использованные компилятором для сохранения оценки слева направо. В этом могут помочь такие инструменты, как sharplab; вот ваш пример в sharplab .

Это связано с 12.4 операторами в спецификации ECMA 334:

12.4.1 Общее

...

Порядок вычисления операторов в выражении определяется приоритетом и ассоциативностью операторов (§12.4.2).

Операнды в выражении оцениваются слева направо. [Пример: В F (i) + G (i ++) * H (i) метод F вызывается с использованием старого значения i, затем метод G вызывается со старым значением i, и, наконец, метод H вызывается с новым значением i. Это отдельно от приоритета оператора и не связано с ним. конец примера]

...