开发者

For Condition VB.NET vs C#

C#:

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;
    }
}

Result (C# rechecks the condition):

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()
    F开发者_Python百科or 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

Result (VB.NET does not recheck the condition):

GetCount
For 1
For 2
For 3
For 4
For 5
For 6
For 7
For 8
For 9
For 10

a) Why doesn't VB.NET respect the "rule" of the recheck the For condition on each iteration?

b) Is there a way to force VB to re-check this condition?


C# and VB.NET are different languages, and similar keywords can have different semantics.

From the docs for For ... Next (my emphasis) :

When a For...Next loop starts, Visual Basic evaluates start, end, and step. This is the only time it evaluates these values.

From section 8.8.3 of the C# specification (ditto):

When and if control reaches the end point of the embedded statement (possibly from execution of a continue statement), the expressions of the for-iterator, if any, are evaluated in sequence, and then another iteration is performed, starting with evaluation of the for-condition in the step above.

If you do want to force the condition to be checked every time, VB.NET offers the extremely flexible Do ... Loop which can have a While or an Until condition, operating at the start or the end of the loop. With that statement, the loop condition is evaluated every time round.


You can achieve the same effect in VB.NET using while(condition).


This is the difference with the compiler. VB.NET compiler just behaves differently.

if you use reflector on the VB.NET one, you see this C# reflected code:

[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();
}

And here is the IL code (note 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

While for the C# code it is different (check is inside the loop):

.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


The VB.NET for-loop doesn't work the same way as the C# one. It says go from this value, to that value. The 'that value' is evaluated once.

The C# one is basically for('initialise stuff';'conditional break stuff';'incremental stuff'), it evaluates the 'conditional break stuff' each time. With a simple for-loop in C# it looks the same as the VB one, but it is (as you've found) working differently.


The reason is that the VB For can be translated into something like this in C#:

int count = GetCount();
for (index = 1; index <= count; index++)
{
}

or, using linq to resemble VB:

foreach(int i in Enumerable.Range(1,GetCount())
{
}

In both cases (and in VB version) GetCount() is called once, hence one call to Console.WriteLine("GetCount") only.


Well, the short answer is they're different languages and they have slightly different takes on this keyword.

In the C#, iteration continues until the termination condition evaluates to false, and it's evaluated on each iteration.

In VB.NET, we iterate one time for each integer value from Start to End (provided the step keyword is not present) and then stop. End is evaluated once at the beginning and that's it.

You could get closer to the C# type of behavior in VB.NET using a Do loop.


the VB.NET For..To loop only needs to call the method once. It stores that value and checks it on each loop iteration. Where the c# for loop calls it on each iteration. You can think of the c# version a fancy syntax for:

index = 1;
while(index <= GetCount()) {
  Console.WriteLine("For {0}", index);
  index++;
}

And if you try to write that in both c# and VB.NET they will operate the same.


As others have said, VB.Net and C# are different languages so these kind of differences can happen.

If you want to force re-evaluation of the loop condition in VB.Net, you have to rewrite the For loop as a While loop

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜