Variable declared inside a for loop. How do I make

2019-02-06 13:46发布

问题:

Today I investigated a logical bug in our software and figured out that this is related to the way VB.NET thread variables inside a loop.

Let's say I have the following code:

    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

produces the following output

1 is Odd
2 is Even
3 is Even
4 is Even
5 is Even

The problem is that isEven is declared but not assigned. In this specific case, it would be correct to write dim isEven as Boolean = false but I haven't done this.

In VB.NET, a variable that is declared inside a for loop keeps its value for the next itaration. This is by design: http://social.msdn.microsoft.com/Forums/en/vblanguage/thread/c9cb4c22-d40b-49ff-b535-19d47e4db38d but this is also dangerous pitfall for programmers.

However, until now, I haven't been aware of this problem/behaviour. Until now. Most of our code base is C# anyway, which doesn't allow the use of an uninitialized variable, so there is no problem.

But we have some legacy code that is written in VB.NET that we have to support.

I don't think that anyone of our dev team has ever used this with purpose. If I explicitly want to share a variable over iterations inside a for loop, I declare it outside the scope.

So the best thing would be to generate a warning or even an error in this specific case. But even with Option Explicit / Option Strict this does not generate a warning / an error.

Is there a way make this a compile time error or maybe a way to check this with FxCop?

回答1:

I don't think that anyone of our dev team has ever used this with purpose. If I explicitly want to share a variable over iterations inside a for loop, I declare it outside the scope.

I suppose the whole point of declaring a variable inside the loop is to explicitly restrict its scope to that block, though. To make this a compile time error would remove block-level scope from the language. While there are certainly cases where method level scope is sensible there can no doubt also be a case made for the importance of block level scope. I don't think you can easily excise this from the language without introducing some new syntactic method for employing it. At this point you are entering the realm of redesigning VB.NET - I'm not sure that there is an easy way to do this.



回答2:

Look at the code below. If not allowing a declaration without an initialization is a compiler error, then this code would not produce the correct output (a running total of even numbers). If you force me to initialize the value of 'total', then the method can never be correct.

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

Instead of adding an error, just fix the logic in the code. I don't see this as a particularly dangerous pitfall. Most programmers would be able to recognize this issue, and unit testing should also help to uncover these types of issues.



回答3:

If you think this may be a problem with your codebase or your programmers, in your coding style specify that all uninitialised variables are declared at the start of the routine. This had been a common style guideline (especially for VB) until the prevalence of type inference.

Of course it doesn't avoid the problem, just makes it more obvious.