Для условия VB.NET vs С#
С#:
static class Module1
{
public static void Main()
{
for (index = 1; index <= GetCount(); index++) {
Console.WriteLine("For {0}", index);
}
Console.ReadKey();
}
public static int GetCount()
{
Console.WriteLine("GetCount");
return 10;
}
}
Результат (С# перепроверяет условие):
GetCount
For 1
GetCount
For 2
GetCount
For 3
GetCount
For 4
GetCount
For 5
GetCount
For 6
GetCount
For 7
GetCount
For 8
GetCount
For 9
GetCount
For 10
GetCount
VB.NET
Module Module1
Sub Main()
For index = 1 To GetCount()
Console.WriteLine("For {0}", index)
Next
Console.ReadKey()
End Sub
Public Function GetCount() As Integer
Console.WriteLine("GetCount")
Return 10
End Function
End Module
Результат (VB.NET не перепроверяет условие):
GetCount
For 1
For 2
For 3
For 4
For 5
For 6
For 7
For 8
For 9
For 10
a) Почему не поддерживает VB.NET "правило" повторного проверки условия For на каждой итерации?
b) Есть ли способ заставить VB повторно проверить это условие?
Ответы
Ответ 1
С# и VB.NET - разные языки, а похожие ключевые слова могут иметь различную семантику.
Из документы для For ... Next
(мой акцент):
При запуске цикла For...Next
Visual Basic оценивает start
, end
и step
. Это единственный раз, когда он оценивает эти значения.
Из раздела 8.8.3 спецификации С# (то же):
Когда и если элемент управления достигает конечной точки встроенного оператора (возможно, из выполнения оператора continue), выражения for-iterator, если они есть, оцениваются последовательно, а затем выполняется другая итерация, начиная с оценки условного условия на предыдущем шаге.
Если вы хотите, чтобы каждое условие принудительно проверялось, VB.NET предлагает чрезвычайно гибкую Do... Loop, которая может иметь условие While или Until, работающее в начале или в конце цикла. С этим утверждением условие цикла оценивается каждый раз.
Ответ 2
VB.NET for-loop работает не так, как С#. Он говорит, что переход от этого значения к этому значению. "Это значение" оценивается один раз.
С# one в основном for('initialise stuff';'conditional break stuff';'incremental stuff')
, он каждый раз оценивает "материал условного прерывания".
С простым for-loop в С# он выглядит так же, как и VB, но он (как вы уже нашли) работает по-другому.
Ответ 3
Вы можете добиться такого же эффекта в VB.NET, используя while(condition)
.
В этом отличие от компилятора. Компилятор VB.NET ведет себя по-другому.
если вы используете отражатель на VB.NET, вы видите этот код с кодом С#:
[STAThread]
public static void Main()
{
int VB$t_i4$L0 = GetCount();
for (int index = 1; index <= VB$t_i4$L0; index++)
{
Console.WriteLine("For {0}", index);
}
Console.ReadKey();
}
И вот код IL (примечание IL_002):
.method public static void Main() cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 )
// Code size 47 (0x2f)
.maxstack 2
.locals init ([0] int32 index,
[1] int32 VB$t_i4$L0,
[2] int32 VB$CG$t_i4$S0)
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: call int32 ConsoleApplication2.Module1::GetCount()
IL_0007: stloc.1
IL_0008: stloc.0
IL_0009: br.s IL_0021
IL_000b: ldstr "For {0}"
IL_0010: ldloc.0
IL_0011: box [mscorlib]System.Int32
IL_0016: call void [mscorlib]System.Console::WriteLine(string,
object)
IL_001b: nop
IL_001c: nop
IL_001d: ldloc.0
IL_001e: ldc.i4.1
IL_001f: add.ovf
IL_0020: stloc.0
IL_0021: ldloc.0
IL_0022: ldloc.1
IL_0023: stloc.2
IL_0024: ldloc.2
IL_0025: ble.s IL_000b
IL_0027: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
IL_002c: pop
IL_002d: nop
IL_002e: ret
} // end of method Module1::Main
В то время как для кода С# он отличается (проверка находится внутри цикла):
.method public hidebysig static void Main() cil managed
{
.entrypoint
// Code size 50 (0x32)
.maxstack 2
.locals init ([0] int32 index,
[1] bool CS$4$0000)
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: stloc.0
IL_0003: br.s IL_001c
IL_0005: nop
IL_0006: ldstr "For {0}"
IL_000b: ldloc.0
IL_000c: box [mscorlib]System.Int32
IL_0011: call void [mscorlib]System.Console::WriteLine(string,
object)
IL_0016: nop
IL_0017: nop
IL_0018: ldloc.0
IL_0019: ldc.i4.1
IL_001a: add
IL_001b: stloc.0
IL_001c: ldloc.0
IL_001d: call int32 Module1::GetCount()
IL_0022: cgt
IL_0024: ldc.i4.0
IL_0025: ceq
IL_0027: stloc.1
IL_0028: ldloc.1
IL_0029: brtrue.s IL_0005
IL_002b: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
IL_0030: pop
IL_0031: ret
} // end of method Module1::Main
Ответ 4
Причина в том, что VB For
может быть переведен на нечто вроде этого в С#:
int count = GetCount();
for (index = 1; index <= count; index++)
{
}
или, используя linq, чтобы походить на VB:
foreach(int i in Enumerable.Range(1,GetCount())
{
}
В обоих случаях (и в версии VB) GetCount()
вызывается один раз, поэтому один вызов только Console.WriteLine("GetCount")
.
Ответ 5
Ну, короткий ответ - это разные языки, и у них немного другое отношение к этому ключевому слову.
В С# итерация продолжается до тех пор, пока условие завершения не станет равным false, и оно будет оцениваться на каждой итерации.
В VB.NET мы повторяем одно время для каждого целочисленного значения от начала до конца (при условии, что ключевое слово шага отсутствует), а затем остановимся. Конец оценивается один раз в начале и что он.
Вы можете приблизиться к типу поведения С# в VB.NET с помощью цикла Do.
Ответ 6
VB.NET For..To цикл нужно только вызвать метод один раз. Он сохраняет это значение и проверяет его на каждой итерации цикла. Где цикл С# for вызывает его на каждой итерации. Вы можете придумать версию С# для фантастического синтаксиса для:
index = 1;
while(index <= GetCount()) {
Console.WriteLine("For {0}", index);
index++;
}
И если вы попытаетесь записать это как в С#, так и в VB.NET, они будут работать одинаково.
Ответ 7
Как говорили другие, VB.Net и С# - разные языки, поэтому такие различия могут произойти.
Если вы хотите принудительно переопределить условие цикла в VB.Net, вы должны переписать цикл For как цикл While