#vb.net #indexoutofrangeexception
Вопрос:
У меня есть код, который я использовал много раз, и который всегда отлично работал для меня. Однако последнее использование вызывает исключение при определенных обстоятельствах, которое я, похоже, не могу разрешить. Вот он:
Я читаю из текстового файла в массив, использую его в качестве источника привязки для некоторых моих элементов управления (он автоматически заполняет 3 элемента управления на основе выбора одного элемента управления). Я создал класс учащихся с 4 свойствами (имя, идентификатор, DOB и DOE). Вот код, который я использую:
Private Sub autoFill()
Dim rost As String = "Roster.txt"
Dim lines As List(Of String) = File.ReadAllLines(rost).ToList
Dim list As List(Of Student) = New List(Of Student)
For i As Integer = 0 To lines.Count - 1
Dim data As String() = lines(i).Split(":")
list.Add(New Student() With {
.StudentName = data(0),
.StudentID = data(1),
.StudentDOB = data(2),
.StudentDOE = data(3)
})
Next
StudentBindingSource.DataSource = list
End Sub
Теперь вот в чем проблема. В цикле «Для», когда я устанавливаю значение i от 0 до строк.количество -1, возникает эта ошибка:
Однако…Если я изменю i на 1 вместо 0, это сработает, ИЛИ если я уберу данные(2) и данные(3), это сработает с i = 0. Я бы предпочел использовать 0, чтобы в выпадающем списке была пустая строка или «—выберите—» и т. Д. Единственное, что я подумал, что может быть полезно, — это то, что моей первой строке в текстовом файле нечего делить. Вот формат строки текстового файла:
Student Name ID# DOB DOE <-----This header row is NOT in the text file
Last Name, First Name : 0000000 : 01/01/2021 : 01/01/2021
Я собираюсь предположить, что мне здесь не хватает чего-то действительно простого. Любые рекомендации будут весьма признательны! Спасибо.
Комментарии:
1. Тогда не анализируйте эту строку, так как она не дает ожидаемых результатов (почему это не так, по — видимому, загадка -у вас есть заголовок? Не имеет значения). Если вам нужно добавить пустой или специальный объект в первый индекс, просто сделайте это. Вы также можете показать баннер Cue в своем выпадающем списке вместо добавления нулевого элемента (
<choose one>
материала). — Вы думали об использовании базы данных для этого?2.
If data.Length = 4 Then
list.Add(New Student() With {....
End If
проверяет, есть ли ровно четыре элемента.3. Я бы предположил, что там есть пустая строка. В любом случае попробуйте изучить/распечатать строки до их анализа (или после сбоя с помощью отладчика). Что-то не так с линией, которая выходит из строя, из-за недостаточного количества двоеточий.
4. Спасибо всем за помощь. Это всего лишь небольшое приложение, которое я использую только на работе, чтобы ускорить свой рабочий процесс. Текстовый файл никогда не будет содержать более 100 строк, и он не сильно изменится, поэтому текстовый файл отлично подходит для моей цели. как оказалось, добавление 4 элементов в первую строку позволило мне начать с индекса 0 и по-прежнему использовать только позицию 0 в строке).
Ответ №1:
Прежде чем мы перейдем к реальной проблеме, давайте кое-что переделаем.
Лучший способ структурировать код, особенно при работе с загрузкой данных, — это иметь метод, который принимает входные данные и возвращает результат. Кроме того, вызов ToList()
или ToArray()
является очень дорогостоящей операцией для производительности. Очень часто вы можете значительно повысить производительность, работая с более низким уровнем IEnumerable
как можно дольше.
Имея в виду эти принципы, рассмотрите этот кодекс:
Private Function ReadStudentData(fileName As String) As IEnumerable(Of Student)
Dim lines As IEnumerable(Of String) = File.ReadLines(fileName)
Return lines.
Select(Function(line) line.Split(":")).
Select(Function(data)
Return New Student() With {
.StudentName = data(0),
.StudentID = data(1),
.StudentDOB = data(2),
.StudentDOE = data(3)
}
End Function)
End Function
Private Sub autoFill()
StudentBindingSource.DataSource = ReadStudentData("Roster.txt")
End Sub
Теперь перейдем к актуальному вопросу. Проблема заключалась не в циклическом переборе list
переменной. Проблема в data
массиве. В какой-то момент у вас есть строка, в которой недостаточно элементов. Это часто встречается, например, как последняя строка в файле.
Есть много способов решить эту проблему. В некоторых случаях исключение уже является подходящим результатом, потому что, если у вас плохие данные, вы действительно не хотите продолжать. В других случаях вы хотите записать неверные записи, возможно, в отчет, который вы можете легко просмотреть позже. Или, может быть, вы просто хотите проигнорировать ошибку или предварительно отфильтровать строки с нужным количеством столбцов. Вот пример последнего варианта:
Private Function ReadStudentData(fileName As String) As IEnumerable(Of Student)
Return File.ReadLines(fileName).
Select(Function(line) line.Split(":")).
Where(Function(data) data.Length = 4).
Select(Function(data)
Return New Student() With {
.StudentName = data(0),
.StudentID = data(1),
.StudentDOB = data(2),
.StudentDOE = data(3)
}
End Function)
End Function
Private Sub autoFill()
StudentBindingSource.DataSource = ReadStudentData("Roster.txt")
End Sub
Комментарии:
1. Это было не только отличным решением для меня, но и исчерпывающим объяснением, которое позволило мне кое-чему научиться! Спасибо!
2. С другой стороны, запуск этого маленького приложения был ПОЛНОЙ потерей ресурсов, и теперь я знаю, почему!
Ответ №2:
Проблема в том, что вы не проверили «данные» на наличие достаточного количества элементов для создания «Ученика». Простая проверка должна это исправить.
Private Sub autoFill()
Dim rost As String = "Roster.txt"
Dim lines As List(Of String) = File.ReadAllLines(rost).ToList
Dim list As List(Of Student) = New List(Of Student)
For i As Integer = 0 To lines.Count - 1
Dim data As String() = lines(i).Split(":"c)
'Check data
If data.Length >= 4 Then '
list.Add(New Student() With {
.StudentName = data(0),
.StudentID = data(1),
.StudentDOB = data(2),
.StudentDOE = data(3)
})
End If
Next
StudentBindingSource.DataSource = list
End Sub
Комментарии:
1. И в этом-то как раз и была проблема, спасибо!
Ответ №3:
попробуйте этот код:
Dim list As List(Of Student) = New List(Of Student)(100)
в основном инициализируйте список учащихся с помощью емкости. Это емкость списка, а не количество/длина.