Циклы С#: итерация через массив - программирование
Подтвердить что ты не робот

Циклы С#: итерация через массив

Если у меня есть цикл, такой как ниже:

foreach (string pass in new string[] { "pass1", "pass2", "pass3" })
{
 x = pass; //etc
}

Создает ли анонимный массив строк один раз изначально или воссоздан один раз для каждого прохода?

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

Код демонтажа VS предполагает, что я прав, но я хочу быть уверенным.

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

4b9b3361

Ответ 1

Согласно блог Эрика Липперта и спецификация, foreach loop - синтаксический сахар для:

{
  IEnumerator<string> e = ((IEnumerable<string>)new string[] { "pass1", "pass2", "pass3" }).GetEnumerator();
   try
   { 
     string pass; // OUTSIDE THE ACTUAL LOOP
      while(e.MoveNext())
      {
        pass = (string)e.Current;
        x = pass;
      }
   }
   finally
   { 
      if (e != null) ((IDisposable)e).Dispose();
   }
}

Как вы можете видеть, перечислитель создается до цикла.

@Rawling правильно указал, что массив обработал немного другой компилятор. Цикл Foreach оптимизирован для цикла с массивами. Согласно Internals of С# foreach ваш код для С# 5 будет выглядеть так:

string[] tempArray;
string[] array = new string[] { "pass1", "pass2", "pass3" };
tempArray = array;

for (string counter = 0; counter < tempArray.Length; counter++)
{
    string pass = tempArray[counter];
    x = pass;
}

Инициализация также происходит только один раз.

Ответ 2

Если вы посмотрите в ILSpy, этот код будет переведен в нечто вроде

string[] array = new string[]
{
    "pass1",
    "pass2",
    "pass3"
};
for (int i = 0; i < array.Length; i++)
{
    string pass = array[i];
}

так что да, массив создается только один раз.

Однако лучше всего убедить своих коллег, вероятно, в разделе 8.8.4 спецификации С#, которая расскажет вам, в чем заключается ответ LazyBerezovsky.

Ответ 3

Он создается только один раз изначально.

Я попробовал предложение Офера Зелига (из комментариев)

foreach (DateTime pass in new DateTime[] { DateTime.Now, DateTime.Now, DateTime.Now })
{
    int x = pass.Second; //etc
}

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

Ответ 4

Вы можете проверить его (много способов сделать это, но это один из вариантов):

string pass4 = "pass4";
foreach (string pass in new string[] { "pass1", "pass2", "pass3", pass4 })
{
    pass4="pass5 - oops";
    x = pass; //etc
}

Затем посмотрите, что выйдет.

Вы обнаружите, что вы правы - его только один раз выполнил.

Ответ 5

Приведенный ниже пример должен ответить на вопрос, воссоздан ли массив или нет.

        int i = 0;
        int last = 0;

        foreach (int pass in new int[] { i++, i++, i++, i++, i++, i++, i++ })
        {
            if (pass != last)
            {
                throw new Exception("Array is reintialized!");
            }
            last++;
        }

        if (i > 7)
        {
            throw new Exception("Array is reintialized!");
        }