Почему цикл 'for' ведет себя по-разному при переносе кода VB.NET на С#?

Я выполняю миграцию проекта с Visual Basic на С#, и мне пришлось изменить способ использования цикла for.

В VB.NET цикл for объявляется ниже:

Dim stringValue As String = "42"

For i As Integer = 1 To 10 - stringValue.Length
   stringValue = stringValue & " " & CStr(i)
   Console.WriteLine(stringValue)
Next

Какие результаты:

42 1
42 1 2
42 1 2 3
42 1 2 3 4
42 1 2 3 4 5
42 1 2 3 4 5 6
42 1 2 3 4 5 6 7
42 1 2 3 4 5 6 7 8

В С# цикл for объявляется ниже:

string stringValue = "42";

for (int i = 1; i <= 10 - stringValue.Length; i ++)
{
   stringValue = stringValue + " " + i.ToString();
   Console.WriteLine(stringValue);
}

И выход:

42 1
42 1 2
42 1 2 3

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

См. Следующий код:

string stringValue = "42";
int stringValueLength = stringValue.Length;

for (int i = 1; i <= 10 - stringValueLength; i ++)
{
   stringValue = stringValue + " " + i.ToString();
   Console.WriteLine(stringValue);
}

И выход:

42 1
42 1 2
42 1 2 3
42 1 2 3 4
42 1 2 3 4 5
42 1 2 3 4 5 6
42 1 2 3 4 5 6 7
42 1 2 3 4 5 6 7 8

Теперь мой вопрос решает, как Visual Basic отличается от С# в терминах Visual Basic, используя условие stringValue.Length в цикле for хотя каждый раз, когда цикл возникает, длина строки изменяется. В то время как в С#, если я использую stringValue.Length в for цикла условия он изменяет начальное значение каждый раз, когда строка, происходит цикл. Почему это?

Ответ 1

В С# условие границы цикла вычисляется на каждой итерации. В VB.NET он оценивается только при входе в цикл.

Итак, в версии С# в вопросе, поскольку длина stringValue изменяется в цикле, значение переменной конечного цикла будет изменено.

В VB.NET конечное условие включено, поэтому вы должны использовать <= вместо < в С#.

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

Ответ 2

Теперь мой вопрос решает, как VB отличается от С# в терминах VB, используя условие stringValue.Length в цикле for, хотя каждый раз, когда цикл возникает, длина строки изменяется.

Согласно документации VB.NET:

Если вы измените значение counter во время цикла, ваш код может быть труднее прочитать и отладить. Изменение значения start, end или step не влияет на значения итерации, которые были определены при первом вводе цикла.

Таким образом, значение To 10 - stringValue.Length оценивается один раз и повторно используется до тех пор, пока циклы не выйдут.

Однако посмотрите на оператор С# for

Если для параметра for_condition нет или если оценка дает значение true, управление передается встроенной инструкции. Когда и если элемент управления достигает конечной точки встроенного оператора (возможно, из выполнения оператора continue), выражения for_iterator, если они есть, оцениваются последовательно, а затем выполняется другая итерация, начиная с оценки for_condition в шаг выше.

Что в основном означает, что условие ; я <= 10 - stringValueLength; ; я <= 10 - stringValueLength; оценивается снова каждый раз.

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

Ответ 3

Чтобы сделать этот пример более понятным, я преобразую оба цикла в циклы С# while.

VB.NET

string stringValue = "42";

int min = 1;
int max = 10 - stringValue.Length;
int i = min;
while (i <= max)
{
    stringValue = stringValue + " " + stringValue.Length.ToString();
    Console.WriteLine(stringValue);
    i++;
}

С#

string stringValue = "42";

int i = 1;
while (i <= 10 - stringValue.Length)
{
    stringValue = stringValue + " " + stringValue.Length.ToString();
    Console.WriteLine(stringValue);
    i++;
}

Разница заключается в следующем:

VB.NET кэширует максимальное значение для i, но С# пересчитывает его каждый раз.

Ответ 4

Поскольку for в VB является другой семантический, чем for в С# (или любого другого С-подобном языке)

В VB оператор for специально увеличивает счетчик от одного значения к другому.

В C, C++, С# и т.д. Оператор for просто оценивает три выражения:

  • Первое выражение обычно является инициализацией
  • Второе выражение оценивается в начале каждой итерации, чтобы определить, выполнено ли условие терминала
  • Третье выражение оценивается в конце каждой итерации, которая обычно является приращением.

В VB вы должны указать числовую переменную, которая может быть протестирована против значения терминала и увеличена на каждой итерации

В C, C++, С# и т.д. Три выражения минимально ограничены; условное выражение должно оцениваться как true/false (или целое число нуль/ненулевое значение в C, C++). Вам вообще не нужно выполнять инициализацию, вы можете перебирать любой тип по любому диапазону значений, перебирать указатель или ссылку на сложную структуру или вообще не перебирать что-либо.

Таким образом, в С# и т.д. Выражение условия должно быть полностью оценено на каждой итерации, но в VB конечное значение итератора должно быть оценено в начале и не нужно снова оценивать.