Vb.net 在for循环内声明的变量。如何将其转换为编译时错误?

Vb.net 在for循环内声明的变量。如何将其转换为编译时错误?,vb.net,for-loop,scope,Vb.net,For Loop,Scope,今天我调查了我们软件中的一个逻辑错误,发现这与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

今天我调查了我们软件中的一个逻辑错误,发现这与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写成Boolean=false是正确的,但我没有这样做

在VB.NET中,在for循环中声明的变量会在下一次初始化时保留其值。这是出于设计:但这对程序员来说也是一个危险的陷阱

然而,直到现在,我还没有意识到这个问题/行为。直到现在。 无论如何,我们的大部分代码库都是C#,它不允许使用未初始化的变量,因此没有问题

但是我们有一些用VB.NET编写的遗留代码需要支持

我不认为我们的开发团队中有人曾经有目的地使用过它。如果我显式地希望在for循环内的迭代中共享一个变量,我会在范围外声明它

因此,在这种情况下,最好是生成一个警告,甚至是一个错误。 但即使使用Option Explicit/Option Strict,也不会生成警告/错误

有没有办法使这成为编译时错误,或者用FxCop检查这一点

我不认为我们的开发团队中有人曾经有目的地使用过它。如果我显式地希望在for循环内的迭代中共享一个变量,我会在范围外声明它


不过,我认为在循环中声明变量的全部目的是显式地将其作用域限制在该块中。若要使其成为编译时错误,将从语言中删除块级范围。虽然在某些情况下方法级范围是合理的,但毫无疑问,块级范围的重要性也是合理的。我认为如果不引入一些新的语法方法来使用它,你很难从语言中删除它。此时,您正进入重新设计VB.NET的领域——我不确定是否有一种简单的方法可以做到这一点。

请查看下面的代码。如果不允许在没有初始化的情况下进行声明是编译器错误,那么此代码将无法生成正确的输出(偶数的运行总数)。如果你强迫我初始化“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

与其添加错误,不如修复代码中的逻辑。我不认为这是一个特别危险的陷阱。大多数程序员都能够认识到这个问题,单元测试也应该有助于发现这些类型的问题。

如果您认为这可能是您的代码库或程序员的问题,请在您的编码风格中指定在例程开始时声明所有未初始化的变量。在类型推断盛行之前,这一直是一个常见的风格指南(特别是对于VB)


当然,这并不能避免这个问题,只是让它变得更加明显。

我不想限制在循环中声明变量,我不想限制在循环中声明变量而不初始化它。这应该被允许
dim someValue as Integer=0
,但这不应该
dim someValue as Integer
,因为后者会引入潜在的危险,因为它会记住是否在下一次初始化中最后分配了值。是的,但部分功能来自于不必对其进行初始化。在块内声明变量块的作用域恰好涉及在每次迭代中运行该行。要执行您建议的操作,将删除具有块范围变量的功能,该变量的值可以在循环迭代中携带。这意味着从没有其他语法暴露它的语言中删除功能。好吧,问题是VB.NET有一些改变编译时行为的能力,就像C#那样:所以我不想破坏任何东西,我想配置编译器。除此之外,如果这不可能,FxCop规则也将是一个解决方案。但是默认的FxCop并不认为这是一个问题。所以真正的问题是,我如何为FxCop创建一个规则来检测方法范围下未初始化的变量?
大多数程序员都能够识别这个问题
——老实说,我没有。在您的示例中,我会将
dim total写成
dim number…
之间的整数,因为我希望每次迭代的total都重置为0。您编写了
,而不是添加错误,只需修复代码中的逻辑,这正是我想要做的。我修复了有问题的代码,但我想知道在我们的遗留代码中还有哪些地方会引入错误。@Schlaviener同样可以认为,对于每个
块,在
之外的复杂代码中声明
总计,引入了能够在其预期使用的块范围之外操纵
总计
的风险。在块内声明它将强制将其范围限制为每个块的
。如果每个
块在
之外不需要
总计
,则最好在块内部声明,而不仅仅是在块外部声明。这与循环中VB.NET线程变量的方式有关:否。你的代码是错误的,它不符合最基本的编程规则:初始化变量。我知道我的代码是错误的,我没有抱怨VB,我在寻求一种方法来避免将来出现这种错误,并在我的遗留代码库中找到可能受此影响的代码。如果我在lambda表达式中使用迭代变量,编译器会警告我,这是一个类似的陷阱:该语言执行命令,但这是p