今天我调查了我们软件中的逻辑错误,并发现这与循环中VB.NET线程变量的方式有关。
假设我有以下代码:
Dim numbers As New List(Of Integer) From {1, 2, 3, 4, 5}
For Each number As Integer In numbers
Dim isEven As Boolean
If number Mod 2 = 0 Then
isEven = True
End If
If isEven Then
Console.WriteLine(number.ToString() & " is Even")
Else
Console.WriteLine(number.ToString() & " is Odd")
End If
Next
产生以下输出
1 is Odd
2 is Even
3 is Even
4 is Even
5 is Even
问题是isEven
已声明但未分配。
在这种特定情况下,写dim isEven as Boolean = false
是正确的,但我没有这样做。
在VB.NET中,在for循环中声明的变量保留其下一个itaration的值。这是设计的:http://social.msdn.microsoft.com/Forums/en/vblanguage/thread/c9cb4c22-d40b-49ff-b535-19d47e4db38d但这对程序员来说也是一个危险的陷阱。
然而,直到现在,我还没有意识到这个问题/行为。到现在。 我们的代码库大部分都是C#,它不允许使用未初始化的变量,所以没有问题。
但我们有一些用VB.NET编写的遗留代码,我们必须支持。
我认为开发团队的任何人都没有用过这个目的。如果我明确想要在for循环内的迭代中共享一个变量,我将它声明在范围之外。
所以最好的办法是在这种特定情况下产生警告甚至错误。 但即使使用Option Explicit / Option Strict,也不会产生警告/错误。
有没有办法让这个编译时错误或者用FxCop检查这个?
答案 0 :(得分:2)
我认为开发团队的任何人都没有用过这个目的。如果我明确想要在for循环内的迭代中共享一个变量,我将它声明在范围之外。
我认为在循环中声明变量的重点是明确地将其范围限制为该块。要使这成为编译时错误,将从语言中删除块级范围。虽然确实存在方法级范围合理的情况,但毫无疑问也存在块级范围重要性的情况。我不认为你可以轻易地从语言中删除它,而不引入一些新的句法方法来使用它。此时您正在进入重新设计VB.NET的领域 - 我不确定是否有一种简单的方法可以做到这一点。
答案 1 :(得分:0)
请看下面的代码。如果在没有初始化的情况下不允许声明是编译器错误,那么此代码将不会产生正确的输出(偶数运行总计)。如果你强迫我初始化'total'的值,那么该方法永远不会是正确的。
Dim numbers As New List(Of Integer) From {1, 2, 3, 4, 5, 6, 8, 9, 10}
For Each number As Integer In numbers
Dim total As Integer
Dim isEven As Boolean = (number Mod 2 = 0)
If isEven Then
total += number
Console.WriteLine("Running Total: {0}", total)
End If
Next
只需修复代码中的逻辑,而不是添加错误。我不认为这是一个特别危险的陷阱。大多数程序员都能够识别这个问题,单元测试也应该有助于发现这些类型的问题。
答案 2 :(得分:0)
如果您认为这可能是您的代码库或程序员的问题,那么在您的编码风格中指定在例程开始时声明所有未初始化的变量。这是一种常见的样式指南(特别是对于VB),直到类型推断的普遍存在。
当然它无法避免这个问题,只是让它更明显。