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

Posted

技术标签:

【中文标题】为啥将 VB.NET 代码迁移到 C# 时,for 循环的行为会有所不同?【英文标题】:Why does a for loop behave differently when migrating VB.NET code to C#?为什么将 VB.NET 代码迁移到 C# 时,for 循环的行为会有所不同? 【发布时间】:2019-03-07 12:53:44 【问题描述】:

我正在将一个项目从 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

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

【问题讨论】:

Microsoft 清楚地概述了您的问题是什么...... @Çöđěxěŕ:请停下。如果在不考虑上下文的​​情况下自动从标题中删除标签是有帮助的,那么网站就会这样做。 @Çöđěxěŕ 你可以找到一些关于here的信息 @Çöđěxěŕ 我不认为这两个帖子相互矛盾。关键是:不要在标题中笨拙地贴上标签,例如“关于这件事的问题 - 标签”。但是如果标题是一个包含标签的完整句子,那么 sometimes 就可以了。 “为什么迁移时 for 循环的行为不同”感觉这个标题太笼统了。 @Çöđěxěŕ“将 VB.NET 代码迁移到 C#”显然是一个完整的短语,为标题添加了有用的信息。不要进行会降低清晰度的编辑。希望这个概念足够常识,我们不需要 Meta 帖子来支持它。 【参考方案1】:

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

所以,在问题的C#版本中,因为stringValue的长度在循环中被改变了,所以最终的循环变量值会被改变。

在 VB.NET 中,最终条件是包容性的,因此您可以在 C# 中使用 &lt;= 而不是 &lt;

C# 中的结束条件评估有一个推论,即使它没有变化但计算成本很高,也应该在循环之前只计算一次。

【讨论】:

感谢您的回复。我现在意识到使用&lt;= 允许我进行迭代并获得与VB 代码相同的输出。但是,我更想知道为什么我必须声明整数变量,而在VB 中我不必这样做。我将更新我的问题以显示相同的输出。 @slee423 原因在我回答的第一句话中给出。因为stringValue的长度在循环中被改变,所以最终的循环变量值会改变。 抱歉,感谢您的回答。感谢您为我详细阐述。 @slee423 我将其添加到答案中,因为它确实澄清了它。【参考方案2】:

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

根据VB.NET 文档:

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

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

不过,看看c#'s for statement

如果for_condition 不存在或者如果评估产生true,则控制转移到嵌入语句。当控制到达嵌入语句的终点时(可能来自执行 continue 语句),for_iterator 的表达式(如果有)将按顺序计算,然后执行另一次迭代,从计算for_condition 在上面的步骤中。

这基本上意味着每次都会重新评估条件; i &lt;= 10 - stringValueLength;

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

【讨论】:

【参考方案3】:

为了使示例更易于理解,我将把两个 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# 每次都会重新计算。

【讨论】:

你不需要将循环转换为while 它帮助我在开始时理解了for loops,我认为它们更容易理解。这就是我“翻译”while loops 中的示例的原因,以帮助理解。【参考方案4】:

因为 VB 中的 for 与 C#(或任何其他类 C 语言)中的 for 语义不同

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

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

第一个表达式通常是初始化 在每次迭代开始时计算第二个表达式以确定是否满足终止条件 第三个表达式在每次迭代结束时计算,这通常是一个增量器。

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

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

所以,在C#等中,条件表达式必须在每次迭代时都被完全求值,而在VB中,迭代器的终值必须在开始时求值,不需要再次求值。

【讨论】:

以上是关于为啥将 VB.NET 代码迁移到 C# 时,for 循环的行为会有所不同?的主要内容,如果未能解决你的问题,请参考以下文章

SpringJdbcTemplate的使用方法

需要帮助将 c# 中的 opencv 转换为 vb.net

将 VB.NET 2.0 Winform 迁移到 3.5 WPF

从 vb.NET (2003) 迁移到 vb2005 都有哪些好处?

如何将 C# 多维列表转换为 VB.Net

如何将带有枚举的 VB.net 接口转换为 C#