变量被赋值之前已经使用了什么意思?

时间:2019-03-14 13:19:50

标签: vb.net

我创建这个程序的目的是对冒泡的“ numbers.txt”文本文件进行排序。但是下面加粗的行给我一个变量变量的错误,该变量在分配值之前已被使用。有人可以帮我吗?我似乎无法弄清这行 numbers2(z)=数字(z)。因为每次我加载该程序时,它都会崩溃。我希望有人能给我一些帮助

 Public Class Form1
    Dim currentLine As String = ""
    Dim data As New System.IO.StreamReader("numbers.txt")
    Dim counter As Integer = 0
    Dim currentValue As Integer
    Dim previousValue As Integer
    Dim nextValue As Integer
    Dim isLoaded As Boolean = False
    Dim numbers As String()
    Dim numbers2 As String()
    Public Sub btnSort_Click(sender As Object, e As EventArgs) Handles btnSort.Click
        If (Not isLoaded) Then
            MessageBox.Show("You have not loaded")
        Else

            For j = 0 To counter
                If (j = 0) Then
                    currentValue = CInt(numbers2(j))
                    nextValue = CInt(numbers2(j + 1))
                    If (currentValue > nextValue) Then
                        numbers2(j + 1) = numbers2(j)
                        numbers2(j) = numbers(j + 1)
                    End If
                ElseIf (j = counter) Then
                    Continue For
                ElseIf (j = counter - 1) Then
                    currentValue = CInt(numbers2(j))
                    previousValue = CInt(numbers2(j - 1))
                    If (currentValue > previousValue) Then
                        'Good
                    ElseIf (currentValue < previousValue) Then
                        numbers2(j - 1) = numbers2(j)
                        numbers2(j) = numbers(j - 1)

                    End If
                Else
                    currentValue = CInt(numbers2(j))
                    previousValue = CInt(numbers2(j - 1))
                    nextValue = CInt(numbers(j + 1))
                    If (currentValue < nextValue) Then
                        'Good
                    ElseIf (currentValue > nextValue) Then
                        numbers2(j + 1) = numbers2(j)
                        numbers2(j) = numbers(j + 1)
                    End If
                    If (currentValue > previousValue) Then
                        'Good
                    ElseIf (currentValue < previousValue) Then
                        numbers2(j - 1) = numbers2(j)
                        numbers2(j) = numbers(j - 1)

                    End If

                End If
            Next

            For k = 0 To counter
                tbOutput.Text += numbers2(k) & vbCrLf
            Next
            For z = 0 To counter
                numbers(z) = numbers2(z)
            Next
        End If
    End Sub

    Public Sub btnLoad_Click(sender As Object, e As EventArgs) Handles btnLoad.Click
        Dim numbers As String() = currentLine.Split(New String() {Environment.NewLine}, StringSplitOptions.None)
        Dim numbers2 As String()

        Do While data.Peek() <> -1
            'Appends currentline with results from data.readline and a new line
            currentLine = currentLine & data.ReadLine() & vbNewLine
            'shows the amount of lines in the file
            counter += 1

        Loop
        'displays content from the file
        tbInput.Text = currentLine
        'sets 

        For z = 0 To counter
            **numbers2(z) = numbers(z)**
        Next

        isLoaded = True
    End Sub

    Private Sub tbOutput_TextChanged(sender As Object, e As EventArgs) Handles tbOutput.TextChanged

    End Sub
End Class

1 个答案:

答案 0 :(得分:3)

从根本上讲,这个问题是在理解变量,对象引用,对象实例和类型之间的差异。在您真的理解这些差异之前,您将继续作为编码人员奋斗。别难过您在这里并不孤单,一旦发现了这一点,一切都会变得很容易。

numbers2变量。与.Net中的所有变量一样,numbers2具有特定的类型:在这种情况下,字符串数组是引用类型。但这与说numbers2本身是一个数组是不一样的。实际数组是 Object 的实例,就像所有对象实例都存在于内存中的与任何变量分开的某个地方一样。您必须给numbers2变量对数组对象的引用。引用将变量与对象连接起来。

该引用不是对象,因为可能有许多引用都指向同一对象。但是,如果没有引用,则对象是无用的,内存将被垃圾收集器回收。引用不是变量,因为一个变量可能在其生命周期内分配了多个不同的引用。但是在分配参考的时间范围内,变量的值就是该参考。并且变量肯定不是(本身)对象。甚至Form1变量也只是对象引用变量,您可以为其分配一个全新的Form1对象实例(VB.Net允许您使用具有相同名称的变量和类型可能会令人沮丧。 ,并且我相信默认情况下使用Windows窗体进行此操作会使许多新程序员在整个“类型vs引用vs对象”区域中产生很多困惑。)

分配引用的一种方法是在创建新对象时。当您在同一行上看到带有Dim关键字的New语句时,就会发生这种情况。当数组的Dim语句包含下标(大小),例如Dim items(4) As StringDim items As String(4)时,也会发生这种情况。此处的编译器将自动创建数组对象。但是,如果您不包括数组(Dim numbers2() As String)的大小,则编译器将没有足够的信息来创建数组,因为它不知道对象需要多大。因此,现在您有了一个对象引用变量,但是还没有分配对象实例。


现在我们已经足够了解开始调试该程序了。

我们将从Load方法开始。此方法的开头重新声明numbersnumbers2数组:

Dim numbers As String() = currentLine.Split(New String() {Environment.NewLine}, StringSplitOptions.None)
Dim numbers2 As String()

这意味着该方法使用的变量与类顶部定义的数组完全不同,因此以后,在Sort方法中没有数据;数组仍然为null / Nothing。

此外,numbers2的声明不分配任何内容。它只是创建一个空数组引用。这不同于具有0个元素的数组对象。 这里根本没有数组对象。这就是导致所指示的行出现异常的原因。您正在尝试为{em>任何对象分配一个numbers2引用变量。


要解决问题,我首先要做的是将事件处理程序与有效的代码分开;将事件代码尽可能地限制为处理读写控制属性的语句。我们将创建一个新的LoadData()函数,该函数接受一个参数并返回一个值。新方法与任何文本框,全局或类变量或控件无关。它仅知道如何以最适合数据的格式读取数据:

Public Function LoadData(fileName As String) As IEnumerable(Of Integer)
     Return File.ReadLines(fileName).Select(Function(line) Integer.Parse(line.Trim()))
End Function

现在,现有的Load方法可以调用此函数。如果此方法根据最适合您的应用程序的方式而不是单击按钮来处理Form_Load,Form_Shown,Form_Activated或类似事件,则更好。另外,让我们为numbers对象选择一个更好的类型:

Private numbers As List(Of Integer)

Public Sub Form1_Load(sender As Object, e As EventArgs) Handles Form1.Load
    numbers = LoadData("numbers.txt").ToList()

    tbInput = String.Join("\n", numbers)
End Sub

我们可以通过删除转换回字符串的方式来提高效率,但是该版本需要更多的代码,并且在您拥有非常大量的收藏之前,它不会产生任何有意义的变化。 / p>

现在让我们看一下排序方法:

 Public Sub btnSort_Click(sender As Object, e As EventArgs) Handles btnSort.Click
    If numbers Is Nothing OrElse numbers.Count = 0 Then
        MessageBox.Show("You have not loaded")
        Return
    End If

    numbers = numbers.OrderBy(Function(n) n).ToList()
    tbOutput.Text = String.Join("\n", numbers)
End Sub

将它们放在一起:

Public Class Form1

    Private numbers As List(Of Integer)

    Public Sub btnSort_Click(sender As Object, e As EventArgs) Handles btnSort.Click
        If numbers Is Nothing OrElse numbers.Count = 0 Then
            MessageBox.Show("You have not loaded")
            Return
        End If

        numbers = numbers.OrderBy(Function(n) n).ToList()
        tbOutput.Text = String.Join("\n", numbers)
    End Sub

    Public Sub Form1_Load(sender As Object, e As EventArgs) Handles Form1.Load
        numbers = LoadData("numbers.txt").ToList()

        tbInput = String.Join("\n", numbers)
    End Sub

    Public Function LoadData(fileName As String) As IEnumerable(Of Integer)
         Return File.ReadLines(fileName).Select(Function(line) Integer.Parse(line.Trim()))
    End Function
End Class

现在,我怀疑这是课程工作,您的讲师不希望您使用OrderBy()Array.Sort()。但即使在那种情况下,也要遵循LoadData()函数的示例:创建一个与按钮事件处理程序分开的方法,该方法接受IEnumerable(Of Integer)并返回排序后的IOrderedEnumerable(Of Integer),然后单击按钮事件处理程序调用此方法。结果将是保留相同基本结构的代码,您仍然只需要一个类级变量。