Реферирование ссылочного типа - новая ссылочная переменная, созданная каждым циклом в цикле, если объявлена ​​в нем?

Это следующее:

MyObject myVariable;
for(int i = 0; i < objects.Length, i++){
  myVariable = objects[i];
  // do stuff...
}

более эффективно:

for(int i = 0; i < objects.Length, i++){
  MyObject myVariable = objects[i];
  // do stuff...
}

потому что новая переменная для хранения ссылки не создается каждый раз? (или является достаточно сложным, достаточно просто использовать одну и ту же переменную).

(Если создается новая переменная, она разделяется на кучу?)

Ответ 1

Нет, "переменные" существуют почти целиком для программиста. Вы не создаете никакой дополнительной работы во время выполнения, объявляя переменную внутри метода.

Теоретически компилятор выделяет пространство в стеке, когда вызывается метод для каждой переменной, объявленной в этом методе. Таким образом, наличие этой переменной в методе будет более важным, чем его объем. В куче не выделяется место, если не используется ключевое слово new.

На практике компилятор может идентифицировать переменные с такой короткой областью, что они могут быть сохранены в регистре CPU, а не в пространстве в стеке. Например:

var a = b[c];
a.ToString();
// never access "a" again.

... будет таким же, как:

b[c].ToString();

... потому что компилятор распознает, что ему достаточно только сохранить результат b [c] достаточно долго, чтобы вызвать метод на нем, поэтому он может просто использовать регистр CPU вместо использования памяти.

По этой причине объявление переменной внутри цикла может фактически заставить метод выделять меньше пространства стека для переменной, в зависимости от возможного логического потока после этого. Тем не менее, это попадает в огромную микро-оптимизацию, которая не имеет никакого смысла для большинства людей, о которых нужно заботиться.

Update

Так как некоторые люди все еще думают, что объявление переменной в цикле имеет некоторый эффект, я думаю, мне нужно предоставить доказательство. В LINQPad введите следующие программы.

int j;
for(int i = 0; i < 5; i++)
{
    j = i;
}

... и...

for(int i = 0; i < 5; i++)
{
    int j = i;
}

Выполните код, затем перейдите на вкладку IL, чтобы увидеть сгенерированный код IL. Это одинаково для обеих этих программ:

IL_0000:  ldc.i4.0    
IL_0001:  stloc.0     
IL_0002:  br.s        IL_0008
IL_0004:  ldloc.0     
IL_0005:  ldc.i4.1    
IL_0006:  add         
IL_0007:  stloc.0     
IL_0008:  ldloc.0     
IL_0009:  ldc.i4.5    
IL_000A:  blt.s       IL_0004

Итак, есть неопровержимое доказательство того, что это не будет иметь никакого значения во время компиляции. Вы получите точно такой же скомпилированный IL из обеих программ.

Ответ 2

короткий ответ, да.

длинный ответ, да, это быстрее, но вряд ли заметно, если не повторять много раз.: -)

Я не уверен, будет ли компилятор оптимизировать его или нет, но я сомневаюсь в этом, и если это так, хорошо для него, вы все равно должны писать так, как будто это не так, сделайте его привычным.