Почему цикл '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 конечное значение итератора должно быть оценено в начале и не нужно снова оценивать.