对于条件 VB.NET 与 C#

本文关键字:VB NET 条件 于条件 | 更新日期: 2023-09-27 17:55:59

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

结果(C# 重新检查条件):

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 重新检查此条件?

对于条件 VB.NET 与 C#

C# 和 VB.NET 是不同的语言,类似的关键字可以有不同的语义。

来自For ... Next文档(我的强调):

For...Next循环启动时,Visual Basic 会计算startendstep这是它唯一一次评估这些值

从 C# 规范的第 8.8.3 节(同上):

当控件到达嵌入语句的终点(可能来自继续语句的执行)时,将按顺序计算 for-iterator 的表达式(如果有),然后执行另一个迭代,从上述步骤中对 for 条件的计算开始

如果您确实想每次都强制检查条件,VB.NET 提供了极其灵活的 Do ...循环,可以具有 While 或 till 条件,在循环的开始结束时运行。使用该语句,每次都会评估循环条件。

您可以使用

while(condition)在 VB.NET 中实现相同的效果。


这是编译器的区别。 VB.NET 编译器的行为不同。

如果在 VB.NET 上使用反射器,则会看到以下 C# 反射代码:

[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

对于 C# 代码,它是不同的(检查是否在循环内):

.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

VB.NET for 循环的工作方式与 C# 循环不同。它说从这个值到那个值。"该值"被评估一次。

C#基本上是for('initialise stuff';'conditional break stuff';'incremental stuff')的,它每次都计算"条件中断的东西"。使用 C# 中的简单 for 循环,它看起来与 VB 循环相同,但它(如您所发现的)工作方式不同。

原因是 VB For可以在 C# 中转换为类似这样的东西:

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

或者,使用 LINQ 类似于 VB:

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

在这两种情况下(以及在VB版本中),GetCount()被调用一次,因此只调用一次Console.WriteLine("GetCount")

好吧,简短的回答是它们是不同的语言,他们对这个关键字的看法略有不同。

在 C# 中,迭代将继续,直到终止条件的计算结果为 false,并在每次迭代时对其进行计算。

在 VB.NET 中,我们对每个整数值从开始到结束迭代一次(前提是 step 关键字不存在),然后停止。结束在开始时被评估一次,仅此而已。

可以使用 Do 循环更接近 VB.NET 中的 C# 行为类型。

VB.NET For..循环只需要调用该方法一次。它存储该值并在每次循环迭代时对其进行检查。其中 c# for 循环在每次迭代时调用它。您可以将 c# 版本视为一种花哨的语法:

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

如果你尝试用 c# 和 VB.NET 编写它,它们的操作将相同。

正如其他人所说,VB.Net 和C#是不同的语言,因此可能会发生这些差异。

如果要在 VB.Net 中强制重新评估循环条件,则必须将 For 循环重写为 While 循环