我创建这个程序的目的是对冒泡的“ 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
答案 0 :(得分:3)
从根本上讲,这个问题是在理解变量,对象引用,对象实例和类型之间的差异。在您真的理解这些差异之前,您将继续作为编码人员奋斗。别难过您在这里并不孤单,一旦发现了这一点,一切都会变得很容易。
numbers2
是变量。与.Net中的所有变量一样,numbers2
具有特定的类型:在这种情况下,字符串数组是引用类型。但这与说numbers2
本身是一个数组是不一样的。实际数组是 Object 的实例,就像所有对象实例都存在于内存中的与任何变量分开的某个地方一样。您必须给numbers2
变量对数组对象的引用。引用将变量与对象连接起来。
该引用不是对象,因为可能有许多引用都指向同一对象。但是,如果没有引用,则对象是无用的,内存将被垃圾收集器回收。引用不是变量,因为一个变量可能在其生命周期内分配了多个不同的引用。但是在分配参考的时间范围内,变量的值就是该参考。并且变量肯定不是(本身)对象。甚至Form1
变量也只是对象引用变量,您可以为其分配一个全新的Form1
对象实例(VB.Net允许您使用具有相同名称的变量和类型可能会令人沮丧。 ,并且我相信默认情况下使用Windows窗体进行此操作会使许多新程序员在整个“类型vs引用vs对象”区域中产生很多困惑。)
分配引用的一种方法是在创建新对象时。当您在同一行上看到带有Dim
关键字的New
语句时,就会发生这种情况。当数组的Dim
语句包含下标(大小),例如Dim items(4) As String
或Dim items As String(4)
时,也会发生这种情况。此处的编译器将自动创建数组对象。但是,如果您不包括数组(Dim numbers2() As String
)的大小,则编译器将没有足够的信息来创建数组,因为它不知道对象需要多大。因此,现在您有了一个对象引用变量,但是还没有分配对象实例。
现在我们已经足够了解开始调试该程序了。
我们将从Load
方法开始。此方法的开头重新声明numbers
和numbers2
数组:
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)
,然后单击按钮事件处理程序调用此方法。结果将是保留相同基本结构的代码,您仍然只需要一个类级变量。