Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

For Condition VB.NET vs C#

Tags:

c#

.net

vb.net

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()
    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

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?

like image 269
serhio Avatar asked May 11 '11 14:05

serhio


5 Answers

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.

like image 160
AakashM Avatar answered Oct 05 '22 23:10

AakashM


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
like image 21
Aliostad Avatar answered Oct 06 '22 01:10

Aliostad


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.

like image 28
George Duckett Avatar answered Oct 06 '22 01:10

George Duckett


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.

like image 27
digEmAll Avatar answered Oct 05 '22 23:10

digEmAll


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.

like image 37
Brian MacKay Avatar answered Oct 05 '22 23:10

Brian MacKay