将VB.NET代码迁移到C#时,为什么for循环的行为会有所不同?


87

我正在将项目从Visual Basic迁移到C#,并且不得不更改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

在C#中,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

现在,我的问题解决stringValue.Length了,for即使每次循环发生时,字符串的长度都会改变,Visual Basic在循环条件下使用Visual Basic在Visual Basic方面与C#有何不同。在C#中,如果我stringValue.Lengthfor循环条件中使用,则每次循环发生时都会更改初始字符串值。为什么是这样?


7
微软清楚地概述你的问题是什么?
Çöđěxěŕ

39
@Çöđěxěŕ:请停下来。如果自动从标题中删除标签而不考虑上下文是有帮助的,则网站会这样做。
Ry-

11
@Çöđěxěŕ您可以在此处
Pushkin '18

35
@Çöđěxěŕ我认为这两个职位并不矛盾。重点是:不要笨拙地在标题中贴上“关于此事的问题-标签”之类的标签。但是,如果标题是包含标签的完整句子,那么有时还可以。“为什么for循环在迁移时的行为会有所不同”,感觉就像是一种过于笼统的标题。
普希金

26
@Çöđěxěŕ“将VB.NET代码迁移到C#”显然是一个完整的短语,在标题中添加了有用的信息。不要进行会降低清晰度的编辑。希望这一概念足够常识,以至于我们不需要Meta帖子来对其进行备份。
jpmc26 '18 -10-2

Answers:


115

在C#中,每次迭代都会评估循环边界条件。在VB.NET中,仅在进入循环时对其进行评估。

因此,在所讨论的C#版本中,由于stringValue在循环中更改的长度,因此最终的循环变量值将被更改。

在VB.NET中,最终条件是包容性的,因此您可以在C#中使用<=代替<

C#中的最终条件评估具有一个推论,即即使它没有变化,但计算起来很昂贵,但它应该在循环之前进行一次计算。


谢谢回复。我现在意识到,使用<=允许我进行迭代并具有与VB代码相同的输出。但是,我更想知道为什么必须声明整数变量,而VB不必这样做。我将更新问题以显示相同的输出。
slee423 '18

@ slee423原因在我回答的第一句话中给出。由于stringValue循环中的长度正在更改,因此最终的循环变量值将被更改。
安德鲁·莫顿

1
抱歉,谢谢您的回答。并感谢您为我详细说明。
slee423 '18 -10-2

1
@ slee423我将其添加到答案中,因为确实可以澄清它。
安德鲁·莫顿

22

现在,我的问题解决了,即使在每次循环发生时,字符串的长度都会改变,但在for循环中使用stringValue.Length条件,VB与C#在VB方面有何不同。

根据VB.NET文档:

如果您counter在循环内更改while的值,则代码可能更难以阅读和调试。改变的值startendstep不影响被当首次进入循环确定的迭代值。

因此,To 10 - stringValue.Length一次评估的值,然后重复使用直到循环退出。

但是,请查看c#的语句

如果for_condition不存在或评估得出true,则控制权转移到嵌入语句。当且如果控制到达嵌入式语句的终点(可能是从执行continue语句开始),for_iterator则按顺序对的表达式(如果有)进行求值,然后执行另一次迭代,从for_condition步骤中的求值开始以上。

这基本上意味着; i <= 10 - stringValueLength;每次都会再次评估该条件。

因此,如您所见,如果要复制代码,则需要在开始循环之前在c#中声明最终计数器。


11

为了使示例更易于理解,我将两个for循环都转换为C# 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++;
}

C#

string stringValue = "42";

int i = 1;
while (i <= 10 - stringValue.Length)
{
    stringValue = stringValue + " " + stringValue.Length.ToString();
    Console.WriteLine(stringValue);
    i++;
}

区别是:

VB.NET缓存的最大值i,但是C#每次都会重新计算它。


2
您无需将循环转换为while
Panagiotis Kanavos

10
它帮助我一for loops开始就理解了,我认为它们更容易理解。这就是为什么我“翻译”中的示例while loops以帮助理解的原因。
Maxime Recuerda '18

7

因为forVB中的in语义不同于forC#中的语义(或任何其他类似C的语言)

在VB中,该for语句专门将计数器从一个值递增到另一个。

在C,C ++,C#等中,该for语句仅计算三个表达式:

  • 第一个表达式通常是一个初始化
  • 在每次迭代的开始对第二个表达式求值,以确定是否满足最终条件
  • 第三个表达式在每次迭代结束时求值,通常是一个增量器。

在VB中,您必须提供一个数字变量,该变量可以针对最终值进行测试,并在每次迭代时递增

在C,C ++,C#等中,这三个表达式的约束最小。条件表达式的计算结果必须为true / false(在C,C ++中为整数零/非零)。您根本不需要执行初始化,可以在任何值的范围内迭代任何类型,在复杂结构上迭代指针或引用,或者根本不进行任何迭代。

因此,在C#等中,必须在每次迭代中完全评估条件表达式,但是在VB中,必须在开始时评估迭代器的最终值,而不必再次评估。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.