Что такое исключение NullReferenceException и как его исправить?

30

c#,.net,vb.net,null,nullreferenceexception,

C # ,. сеть, vb.net, нуль, NullReferenceException,

Ответов: 1878


2127 принят

В чем причина?

Нижняя линия

Вы пытаетесь использовать что-то, что есть a(или if (a.HasValue) {...}в VB.NET). Это означает, что вы либо установили его if (a==null) {...}, либо никогда не устанавливали его вообще.

Как и все остальное, aвсе проходит. Если a.Value в методе «A», может быть , что метод «B» прошел a к методу «A».

a.Value могут иметь разные значения:

  1. Объектные переменные неинициализируются и, следовательно, указывают на InvalidOperationException. В этом случае, если вы обращаетесь к свойствам или методуNullReferenceException для таких объектов, это вызывает a a.
  2. Разработчик с помощью nullнамеренно , чтобы указать , что нет смысла доступного значения. Обратите внимание, что C # имеет int b; cept of if (a.HasValue) {b = a.Value; } способные типы данных для переменных (например, таблицы базы данных могут иметь (a! = null) {b = a;} способное исключение fielNullReferenceException) - вы можете назначить NullReferenceExceptionим указать, что в нем нет значения, например, nullгде знак вопроса указывает разрешено хранить значение null в переменной a. Вы можете проверить это либо с помощью, string foo = null; foo.ToUpper(); либо с NullReferenceException. Переменные, aдоступные в ToUpper (), как этот пример, позволяют получить доступ к значению через stringявное или просто нормальное значение a.
    Обратите внимание, что доступ к нему через nullthrows NullReferenceExceptionвместо a ref1.ref2.ref3.member if ais NullReferenceException- вы должны сделать проверку заранее, то есть, если у вас есть другой on-var r1 = ref1; var r2 = r1.ref2; var r3 = r2.ref3; r3.member, HttpContext.Current.User.Identity.Nameто вы должны делать присваивания вроде HttpContext.Currentили короче User.

В остальной части этой статьи более подробно рассматриваются ошибки, которые часто делают многие программисты, которые могут привести к Identity.

Более конкретно

Среда выполнения public class Person { public int Age { get; set; } } public class Book { public Person Author { get; set; } } public class Example { public void Foo() { Book b1 = new Book(); int authorAge = b1.Author.Age; // You never initialized the Author property. // there is no Person to get an Age from. } } всегда означает одно и то же: вы пытаетесь использовать ссылку, и ссылка не инициализируется (или она была однажды инициализирована, но больше не инициализирована).

Это означает, что ссылка есть Book b1 = new Book { Author = { Age = 45 } }; , и вы не можете получить доступ к элементам (таким как методы) через Book b1 = new Book(); b1.Author.Age = 45; ссылку. Простейший случай:

new

Это будет Bookвызывать на второй строке, потому что вы не можете вызвать метод экземпляра Personна Authorссылку, указывающую на null.

отладка

Как вы находите источник public class Person { public ICollection<Book> Books { get; set; } } public class Book { public string Title { get; set; } } ? Помимо рассмотрения самого исключения, которое будет выбрасываться точно в том месте, где оно происходит, применяются общие правила отладки в Visual Studio: размещайте стратегические точки останова и проверяйте свои переменные , наведя указатель мыши на их имена, Person p1 = new Person {Books = {new Book {Title = "Title1"}, новая книга {Title = "Title2"},}}; (Quick) Watch или с использованием различного отладочного Person p1 = new Person (); p1.Books.Add (новая книга {Title = "Title1"}); p1.Books.Add (новая книга {Title = "Title2"}); как местные жители и автомобили.

Если вы хотите узнать, где ссылка или не установлена, щелкните ее имя правой кнопкой мыши и выберите «Найти все ссылки». Затем вы можете разместить точку останова в каждом найденном месте и запустить свою программу с прикрепленным отладчиком. Каждый раз, когда отладчик разбивается на такую ??точку останова, вам нужно определить, считаете ли вы, что ссылка является не-новым Лицом, проверите переменную и убедитесь, что она указывает на экземпляр, когда вы ожидаете этого.

Таким образом, следуя программному потоку, вы можете найти место, где экземпляр не должен быть Лицом, и почему он неправильно установлен.

Примеры

Некоторые распространенные сценарии, в которых может быть выбрано исключение:

общий

Books

Если ref1 или ref2 или ref3 равно null, вы получите a p1.Books. Если вы хотите решить проблему, то выясните, какой из них p1.Books.Add (...), переписывая выражение в его более простой эквивалент:

int[] numbers = null;
int n = numbers[0]; // numbers is null. There is no array to index.

В частности, в Person[] people = new Person[5]; people[0].Age = 20 // people[0] is null. The array was allocated but not // initialized. There is no Person to set the Age for. , long[][] array = new long[1][]; array[0][0] = 3; // is null because only the first dimension is yet initialized. // Use array[0] = new long[2]; first. может быть Dictionary <string, int> agesForNames = null; int age = ageForNames ["Bob"]; // ageForNames имеет значение null. // Нет словаря для выполнения поиска. , или public class Person { public string Name { get; set; } } var people = new List<Person>(); people.Add(null); var names = from p in people select p.Name; string firstName = names.First(); // Exception is thrown here, but actually occurs // on the line above. "p" is null because the // first element we added to the list is null. свойство может быть публичным классом Demo {public event EventHandler StateChanged; защищенный виртуальный void OnStateChanged (EventArgs e) {StateChanged (this, e); // Здесь вызывается исключение // если обработчики событий не были привязаны // к событию StateChanged}}, или public class Form1 { private Customer customer; private void Form1_Load(object sender, EventArgs e) { Customer customer = new Customer(); customer.Name = "John"; } private void Button_Click(object sender, EventArgs e) { MessageBox.Show(customer.Name); } } свойство может быть частным клиентом _customer; ,

непрямой

public partial class Issues_Edit : System.Web.UI.Page
{
    protected TestIssue myIssue;

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            // Only called on first load, not when button clicked
            myIssue = new TestIssue(); 
        }
    }

    protected void SaveButton_Click(object sender, EventArgs e)
    {
        myIssue.Entry = "NullReferenceException here!";
    }
}

Если вы хотите избежать дочернего элемента (// если значение сеанса «FirstName» еще не установлено, //, то эта строка будет вызывать строку NullReferenceException firstName = Session ["FirstName"]. ToString ();) Ссылка @Model , вы можете инициализировать его в конструкторе объекта parent (Model).

Вложенные инициализаторы объектов

То же самое относится к инициализаторам вложенных объектов:

return

Это переводит

// Controller
public class Restaurant:Controller
{
    public ActionResult Search()
    {
         return View();  // Forgot the provide a Model here.
    }
}

// Razor view 
@foreach (var restaurantSearch in Model.RestaurantSearch)  // Throws.
{
}

<p>@Model.somePropertyName</p> <!-- Also throws -->

Хотя InitializeComponentключевое слово используется, оно создает только экземпляр NullReferenceException Book, но не экземпляр InitializeComponent <Grid> <!-- Combobox declared first --> <ComboBox Name="comboBox1" Margin="10" SelectedIndex="0" SelectionChanged="comboBox1_SelectionChanged"> <ComboBoxItem Content="Item 1" /> <ComboBoxItem Content="Item 2" /> <ComboBoxItem Content="Item 3" /> </ComboBox> <!-- Label declared later --> <Label Name="label1" Content="Label" Margin="10" /> </Grid> , поэтому comboBox1свойство остается label1.

Инициализаторы вложенной коллекции

comboBox1_SelectionChanged

Инициализаторы вложенных коллекций ведут себя одинаково:

private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    label1.Content = comboBox1.SelectedIndex.ToString(); // NullReference here!!
}

Это переводит

label1

comboBox1Только создает экземпляр Person, но NullReferenceExceptionколлекция до сих пор as. Синтаксис инициализатора коллекции не создает коллекцию var myThing = someObject as Thing; , она только переводит в nullоператоры.

массив

First()

Элементы массива

Single()

Жесткие массивы

foreach

Коллекция / нуль / Словарь

 List<int> list = null;    
 foreach(var v in list) { } // exception

Переменная диапазона (косвенная / отложенная)

 foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))

Мероприятия

null

Плохие соглашения об именах:

Если вы назвали поля по-разному от местных, вы, возможно, поняли, что вы никогда не инициализировали это поле.

null

Это можно решить, выполнив соглашение с префиксными полями с помощью подчеркивания:

void PrintName(Person p) {
    if (p != null) {
        Console.WriteLine(p.Name);
    }
}

Жизненный цикл страницы ASP.NET:

null

Значения сеанса ASP.NET

null

Пустая строка представления ASP.NET MVC GetCategory (книга b) {if (b == null) return "Unknown"; return b.Category; } s

Если это исключение возникает при ссылке на свойство nullв представлении ASP.NET MVC, вам нужно понять, что Modelв вашем методе действия устанавливается, когда вы string GetCategory(string bookTitle) { var book = library.FindBook(bookTitle); // This may return null if (book == null) throw new BookNotFoundException(bookTitle); // Your custom exception return book.Category; } видите. Когда вы возвращаете пустую модель (или свойство модели) с вашего контроллера, исключение возникает, когда представления обращаются к нему:

Debug.Assert

Порядок создания WPF-контроля и события

Во время вызова в WPD создаются нулевые значения WPF nullв порядке их появления в визуальном дереве. A Debug.Assert()будет поднят в случае ранней созданной строки GetTitle (int knownBookID) {// Вы знаете, что это никогда не должно возвращать null. var book = library.GetBook (knownBookID); // Исключение будет происходить на следующей строке, а не в конце этого метода. Debug.Assert (book! = Null, «Библиотека не вернула книгу для известного идентификатора книги»); // Некоторый другой код return book.Title; // Никогда не будет вызывать исключение NullReferenceException в режиме отладки. } с обработчиками событий и т. д., которые срабатывают, в течение NullReferenceExceptionкоторых эталонная поздняя книга == null.

Например :

GetValueOrDefault()

Здесь nullсоздается прежде DateTime? appointment = null; Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now)); // Will display the default value provided (DateTime.Now), because appointment is null. appointment = new DateTime(2022, 10, 20); Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now)); // Will display the appointment date, not the default . Если ??попытки ссылаться на `If (), он еще не создан.

null

Изменение порядка деклараций в XAML (т.е. листинг label1до того IService CreateService(ILogger log, Int32? frobPowerLevel) { var serviceImpl = new MyService(log ?? NullLog.Instance); // Note that the above "GetValueOrDefault()" can also be rewritten to use // the coalesce operator: serviceImpl.FrobPowerLevel = frobPowerLevel ?? 5; } , игнорируя вопросы философии дизайна, по крайней мере разрешить ?.здесь.

Бросьте as

?[x]

Это не вызывает InvalidCastException, но возвращает a, var title = person.Title.ToUpper(); когда сбой выполняется (и когда someObject сам является ToUpper). Поэтому имейте это в виду.

LINQ var title = person.Title == null? null: person.Title.ToUpper (); () и SingleOrDefault ()

Обычные версии var title = person.Title?.ToUpper(); и nullисключение, если есть ToUpper. В этом случае версии «OrDefault» возвращают null. Поэтому имейте это в виду.

person.Title

nullбросает при попытке итерации нулевой коллекции. Обычно вызвано неожиданным nullрезультатом методов, возвращающих коллекции.

title

Более реалистичный пример - выбор узлов из XML ??. Будут выбрасываться, если узлы не найдены, но первоначальная отладка показывает, что все свойства действительны:

// regular null check
int titleLength = 0;
if (title != null)
    titleLength = title.Length; // If title is null, this would throw NullReferenceException

// combining the `?` and the `??` operator
int titleLength = title?.Length ?? 0;

Способы избежать

Явно проверьте nullи проигнорируйте нулевые значения.

Если вы ожидаете, что ссылка иногда будет нулевой, вы можете проверить ее nullдо доступа к членам экземпляра:

?[i]

Явно проверьте nullи укажите значение по умолчанию.

Вызов метода, который вы ожидаете вернуть, может возвратиться null, например, когда искомый объект не найден. Вы можете выбрать значение по умолчанию, если это так:

int[] myIntArray=null;
var i=5;
int? elem = myIntArray?[i];
if (!elem.HasValue) Console.WriteLine("No value");

Явно проверяю nullвызовы методов и вытаскиваю специальное исключение.

Вы также можете создать настраиваемое исключение, только для elem = myIntArray [i]; это в вызывающем коде:

public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
{
    for (int i = 0; i < count; ++i)
      yield return f.MakeFrob();
}
...
FrobFactory factory = whatever;
IEnumerable<Frobs> frobs = GetFrobs();
...
foreach(Frob frob in frobs) { ... }

Используйте, whateverесли значение никогда не должно быть null, чтобы обнулить проблему раньше, чем возникает исключение.

Когда вы знаете во время разработки, что метод, возможно, может, но никогда не должен возвращаться null, вы можете использовать, MakeFrobчтобы как можно скорее сломаться, когда это произойдет:

// DON'T DO THIS
public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
{
    if (f == null) 
      throw new ArgumentNullException("f", "factory must not be null");
    for (int i = 0; i < count; ++i)
      yield return f.MakeFrob();
}

Хотя эта проверка не закончится в вашей сборке релизов , заставляя ее снова бросать, foreachкогда GetFrobsво время выполнения в режиме выпуска.

Используйте // DO THIS public IEnumerable<Frob> GetFrobs(FrobFactory f, int count) { // No yields in a public method that throws! if (f == null) throw new ArgumentNullException("f", "factory must not be null"); return GetFrobsForReal(f, count); } private IEnumerable<Frob> GetFrobsForReal(FrobFactory f, int count) { // Yields in a private method Debug.Assert(f != null); for (int i = 0; i < count; ++i) yield return f.MakeFrob(); } типы значений GetFrobsullable, чтобы предоставить значение по умолчанию, когда они есть null.

GetFrobsForReal

Используйте нулевой коалесцирующий оператор: NullReference Exception[C #] или NullReferenceException[VB].

Сокращение до предоставления значения по умолчанию, когда nullвстречается:

Nothing

Используйте оператор null condition: Nothingили Nothingдля массивов (доступных в C # 6 и VB.NET 14):

Это также иногда называют безопасной навигацией или Элвисом (после его формы). Если выражение в левой части оператора равно NULL, то правая сторона не будет оцениваться, а вместо него будет возвращена нуль. Это означает такие случаи:

MsgBox

Если у человека нет названия, это вызовет исключение, потому что оно пытается вызвать Error while...свойство с нулевым значением.

В C # 5 и ниже это можно защитить:

Locals Window

Теперь переменная title будет равна null вместо исключения исключения. C # 6 вводит более короткий синтаксис для этого:

Dim reg As CashRegister
...
TextBox1.Text = reg.Amount         ' NRE

Это приведет к тому, что переменная title будет null, и вызов Dimне будет выполнен, если regесть null.

Конечно, вам все равно нужно проверить значение titlenull или использовать оператор нулевого условия вместе с нулевым коалесцирующим оператором ( New) для предоставления значения по умолчанию:

Dim reg As New CashRegister        ' [New] creates instance, invokes the constructor

' Longer, more explicit form:
Dim reg As CashRegister = New CashRegister

Аналогично, для массивов вы можете использовать Private reg As CashRegister ' Declare ... reg = New CashRegister() ' Create instance следующее:

Dim

Это сделает следующее: Если myIntArray имеет значение null, выражение возвращает null, и вы можете спокойно его проверить. Если он содержит массив, он будет делать то же самое, что Sub Newи возвращает i- й элемент.

Специальные методы для отладки и исправления нулевых дереф в итераторах

C # поддерживает «блоки итератора» (называемые «генераторами» на некоторых других популярных языках). Исключения исключений в виде исключений могут быть особенно сложными для отладки в блоках итератора из-за отложенного выполнения:

Private reg As CashRegister
'...

Public Sub New()
   '...
   Dim reg As New CashRegister
End Sub

Если regрезультаты nullтогда regбудут бросать. Теперь вы можете подумать, что правильно это сделать:

Scope

Почему это неправильно? Поскольку блок итератора фактически не работает до тех пор, пока не будет foreach! Вызов Nothingпросто возвращает объект, который при повторении запускает блок итератора.

Написав нулевую проверку, вы избегаете нулевой разыменования, но переместите исключение нулевого аргумента в точку итерации , а не на точку вызова , и это очень запутанно для отладки .

Правильное исправление:

New

То есть, создайте вспомогательный метод исключений NullReference, который имеет логику блока итератора, и метод открытой поверхности, который выполняет нулевую проверку и возвращает итератор. Теперь, когда Newвызывается, нулевая проверка происходит немедленно, а затем Newвыполняется, когда последовательность повторяется.

Если вы изучите источник ссылок для LINQ to Objects, вы увидите, что этот метод используется повсюду. Это немного сложнее писать, но значительно облегчает отладку ошибок с ошибками. Оптимизируйте свой код для удобства вызывающего абонента, а не для удобства автора .

Замечание о нулевых различиях в небезопасном коде

C # имеет «небезопасный» режим, который, как следует из названия, чрезвычайно опасен, поскольку обычные механизмы безопасности, обеспечивающие безопасность памяти и безопасность типов, не применяются. Вы не должны писать небезопасный код, если у вас нет глубокого понимания того, как работает память .

В небезопасном режиме вы должны знать два важных факта:

  • разыменование нулевого указателя вызывает то же исключение, что и разыменование нулевой ссылки
  • разыменование недействительного ненулевого указателя может привести к этому исключению при некоторых обстоятельствах

Чтобы понять, почему это так, это помогает понять, как .NET в первую очередь создает исключения нулевой разницы. (Эти сведения относятся к .NET, работающему в Windows, другие операционные системы используют аналогичные механизмы.)

Память виртуализирована в Windows; каждый процесс получает пространство виртуальной памяти из многих «страниц» памяти, которые отслеживаются операционной системой. На каждой странице памяти установлены флаги, определяющие способ их использования: чтение, запись, выполнение и т. Д. Самая низкая страница отмечена как «выдавать ошибку, если она когда-либо используется».

И нулевой указатель, и нулевая ссылка в C # внутренне представлены как числовое значение нуль, и поэтому любая попытка разыменовать его в соответствующем хранилище памяти приводит к тому, что операционная система создает ошибку. Затем среда выполнения .NET обнаруживает эту ошибку и превращает ее в исключение нулевого исключения.

Вот почему разыменование нулевого указателя и нулевой ссылки приводит к тому же исключению.

Как насчет второго пункта? Выделение любого недействительного указателя, попадающего на самую низкую страницу виртуальной памяти, вызывает ту же ошибку операционной системы и тем самым одно и то же исключение.

Почему это имеет смысл? Ну, предположим, что у нас есть структура, содержащая два ints, а неуправляемый указатель равен нулю. Если мы попытаемся разыменовать второй int в структуре, CLR не будет пытаться получить доступ к хранилищу при нулевом местоположении; он получит доступ к хранилищу в четвертом месте. Но логически это нулевое разыменование, потому что мы получаем этот адрес через нуль.

Если вы работаете с небезопасным кодом, и вы получаете исключение с помощью исключаемого исключения, просто имейте в виду, что указатель-нарушитель не должен иметь значение null. Это может быть любое местоположение на самой низкой странице, и это исключение будет создано.


278 ов

Dim - Visual Basic

NullReference ExceptionДля Visual Basic ничем не отличается от такового в C # . В конце концов, они оба сообщают об одном и том же исключении, определенном в .NET Framework, которое они оба используют. Причины, уникальные для Visual Basic, встречаются редко (возможно, только один).

В этом ответе будут использоваться термины, синтаксис и контекст Visual Basic. Используемые примеры исходят из большого количества прошлых вопросов о переполнении стека. Это максимально уместность, используя виды ситуаций , часто видели в сообщениях. Немного больше объяснений также предоставляется тем, кому это может понадобиться. Пример, похожий на ваш, очень вероятно указан здесь.

Заметка:

  1. Это основано на концепции: в вашем проекте нет кода для вставки. Он призван помочь вам понять, что вызывает Private(NRE), как его найти, как его исправить, и как его избежать. NRE может быть вызвано многими способами, поэтому это вряд ли будет вашей единственной встречей.
  2. Примеры (из Stack Overflow posts) не всегда показывают лучший способ сделать что-то в первую очередь.
  3. Как правило, используется самое простое средство.

Основное значение

Сообщение «Объект, не установленный для экземпляра объекта» означает, что вы пытаетесь использовать объект, который не был инициализирован. Это сводится к одному из следующих:

  • Ваш код объявлял объектную переменную, но не инициализировал ее (создайте экземпляр или «создайте экземпляр »)
  • Что-то, что предполагал ваш код, инициализирует объект, не
  • Возможно, другой код преждевременно аннулировал объект, который все еще используется

Поиск причины

Поскольку проблема является ссылкой на объект Type, то есть ответ заключается в том, чтобы изучить их, чтобы выяснить, какой из них. Затем определите, почему он не инициализирован. Держите мышь над различными переменными, и Visual Studio (VS) покажет их значения - виновником будет Private | Friend | Public.

IDE debug display

Вы также должны удалить любые Try / Private arr как String () блоки из соответствующего кода, особенно те, где есть Private arr as String () = New String (10) {} 'или Private arr () As String = New String ( 10) {} 'Для локального массива (в процедуре) и использования «Option Infer»: Dim arr = New String (10) {} в блоке Option Infer. Это приведет к сбою вашего кода при попытке использовать объект, который есть As <Type>. Это то, что вы хотите, потому что оно идентифицирует точное местоположение проблемы и позволяет идентифицировать вызывающий объект.

A Newв Catch, который отображает Dim myDbl As Double() = {1.5, 2, 9.9, 18, 3.14} Dim myDbl = New Double() {1.5, 2, 9.9, 18, 3.14} Dim myDbl() = {1.5, 2, 9.9, 18, 3.14} , мало поможет. Этот метод также приводит к очень плохим вопросам переполнения стека, потому что вы не можете описать фактическое исключение, объект или даже строку кода, где это происходит.

Вы также можете использовать As <Type>( Debug -> Windows -> Locals ) для изучения ваших объектов.

Как только вы знаете, что и где проблема, его обычно довольно легко исправить и быстрее, чем опубликовать параметр Strict.

Смотрите также:

Примеры и средства защиты

Объекты класса / Создание экземпляра

Private myDoubles As Double() = {1.5, 2, 9.9, 18, 3.14}

Проблема заключается в том, Dim arrFoo(5) As Foo For i As Integer = 0 To arrFoo.Count - 1 arrFoo(i).Bar = i * 10 ' Exception Next что не создается объект CashFooister ; он объявляет только переменную с именем For i As Integer = 0 To arrFoo.Count - 1 arrFoo(i) = New Foo() ' Create Foo instance arrFoo(i).Bar = i * 10 Next этого типа. Объявление переменной объекта и создание экземпляра - это две разные вещи.

средство

List(Of T)Оператор часто может быть использован для создания экземпляра при объявлении его:

Dim FooList As New List(Of Foo)     ' List created, but it is empty
Dim f As Foo                        ' Temporary variable for the loop

For i As Integer = 0 To 5
    f = New Foo()                    ' Foo instance created
    f.Bar =  i * 10
    FooList.Add(f)                   ' Foo object added to list
Next

Когда целесообразно создать экземпляр позже:

Private myList As List(Of String)
..
myList.Add("ziggy")           ' NullReference

Примечание. Не используйте myListснова в процедуре, включая конструктор ( myList = New List(Of String) ' Or create an instance when declared: Private myList As New List(Of String) ):

Type

Это создаст локальную переменную, Public Class Foo Private barList As List(Of Bar) Friend Function BarCount As Integer Return barList.Count End Function Friend Sub AddItem(newBar As Bar) If barList.Contains(newBar) = False Then barList.Add(newBar) End If End Function которая существует только в этом контексте (sub). regПеременной с уровнем модуля , Scopeкоторый вы будете использовать везде остается barList.

Отсутствие Fooоператора - причина №1,barList рассмотренная в рассмотренных вопросах переполнения стека.

Visual Basic пытается многократно очистить процесс, используя Public Sub New ' Constructor ' Stuff to do when a new Foo is created... barList = New List(Of Bar) End Sub : Использование Newоператора создает новый объект, а вызовы Public Sub New() ' Creates another barList local to this procedure Dim barList As New List(Of Bar) End Sub - конструктор, где ваш объект может использовать любую другую инициализацию perList (Of T).

Чтобы быть ясным, Command(или Private) объявляет только переменную и ее Type. Объем переменной - существует ли она для всего модуля / класса или является локальным для процедуры - определяется , где она объявлена. Connectionопределяет уровень доступа, а не область действия .

Для получения дополнительной информации см.


Массивы

Массивы также должны быть созданы:

Transaction

Этот массив только объявлен, а не создан. Существует несколько способов инициализации массива:

Dataset

Примечание: Начиная с VS 2010, при инициализации локального массива с использованием литерала и DataTable, DataRowsи Newэлементы являются необязательными:

Dim da As OleDbDataAdapter
Dim ds As DataSet
Dim MaxRows As Integer

con.Open()
Dim sql = "SELECT * FROM tblfoobar_List"
da = New OleDbDataAdapter(sql, con)
da.Fill(ds, "foobar")
con.Close()

MaxRows = ds.Tables("foobar").Rows.Count      ' Error

Тип данных и размер массива выводятся из назначаемых данных. Декларации класса / уровень модуля все еще требуют dsс DataAdapter:

DataSet

Пример: массив объектов класса

ds

Массив создан, но conв нем нет объектов.

средство

Dim ds As New DataSet

Использование ds = New DataSet da = New OleDBDataAdapter(sql, con) da.Fill(ds, "Employees") txtID.Text = ds.Tables("Employee").Rows(0).Item(1) txtID.Name = ds.Tables("Employee").Rows(0).Item(2) воли довольно сложно иметь элемент без действительного объекта:

Employees

Для получения дополнительной информации см.


Списки и коллекции

Коллекции .NET (из которых есть много разновидностей - Списки, Словарь и т. Д.) Также должны быть созданы или созданы.

Employee

Вы получаете одно и то же исключение по той же причине - DataTableбыло объявлено только, но экземпляр не создан. Средство защиты одно и то же:

NullReferenceException

Общий надзор - это класс, который использует коллекцию Type:

Items

Любая процедура приведет к NRE, потому что Tables(0)объявляется, а не создается. Создание экземпляра Rows.Countне будет также создавать экземпляр внутреннего If ds.Tables(0).Rows.Count > 0 Then txtID.Text = ds.Tables(0).Rows(0).Item(1) txtID.Name = ds.Tables(0).Rows(0).Item(2) End If . Возможно, это было намерение сделать это в конструкторе:

Fill

Как и раньше, это неверно:

Rows

Дополнительные сведения см . В разделе If da.Fill(ds, "Employees") > 0 Then... Класс .


Объекты поставщика данных

Работа с базами данных представляет много возможностей для NullReference , потому что может быть много объектов ( Dim da As New OleDb.OleDbDataAdapter("SELECT TICKET.TICKET_NO, TICKET.CUSTOMER_ID, ... FROM TICKET_RESERVATION AS TICKET INNER JOIN FLIGHT_DETAILS AS FLIGHT ... WHERE [TICKET.TICKET_NO]= ...", con) Dim ds As New DataSet da.Fill(ds) If ds.Tables("TICKET_RESERVATION").Rows.Count > 0 Then , DataAdapter, TableNames, ds.Tables("TICKET_RESERVATION"), If ds.Tables(0).Rows.Count > 0 Then , If myFoo.Bar.Items IsNot Nothing Then ... ....) в использовании сразу. Примечание. Неважно, какой поставщик данных вы используете - MySQL, SQL Server, OleDB и т. Д. - концепции одинаковы.

Пример 1

Items

Как и прежде, dsобъект myFoo был объявлен, но экземпляр никогда не создавался. BarВоля Если (MYFOO IsNot Nothing) AndAlso (myFoo.Bar IsNot Nothing) AndAlso (myFoo.Bar.Items не IsNot Nothing) Тогда .... существующий DataSet, не создать. В этом случае, поскольку dsэто локальная переменная, IDE предупреждает вас, что это может произойти:

img

Когда объявляется как переменная уровня модуля / класса, как представляется con, компилятор не может знать, был ли объект создан процедурой восходящего потока. Не игнорируйте предупреждения.

средство

AndAlso

Пример 2.

False

Опечатка проблема здесь: myFoo.Barпротив myFoo. Не было myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename") создано никакого имени «Сотрудник», поэтому nullрезультаты пытаются получить к нему доступ. Другая потенциальная проблема заключается в том, что будет, myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value" что может быть и так, когда SQL включает предложение WHERE.

средство

Поскольку это использует одну таблицу, использование myWebBrowserпозволит избежать орфографических ошибок. Изучение Documentтакже может помочь:

formfld1

Fillэто функция, возвращающая число Rowsзатронутых, которые также могут быть протестированы:

Dim cmd5 As New SqlCommand("select Cartons, Pieces, Foobar " _
     & "FROM Invoice where invoice_no = '" & _
     Me.ComboBox5.SelectedItem.ToString.Trim & "' And category = '" & _
     Me.ListBox1.SelectedItem.ToString.Trim & "' And item_name = '" & _
     Me.ComboBox2.SelectedValue.ToString.Trim & "' And expiry_date = '" & _
     Me.expiry.Text & "'", con)

Пример 3.

ListBox1.SelectedItem

Предоставление Nothingбудет ListBox1.SelectedItem.ToStringпоказано в предыдущем примере, но оно не анализирует имена из таблицы SQL или базы данных. В результате Option Strictссылки на несуществующую таблицу.

Устранение такой же, ссылки на таблицу с помощью индекса:

Dim expiry As DateTime         ' for text date validation
If (ComboBox5.SelectedItems.Count > 0) AndAlso
    (ListBox1.SelectedItems.Count > 0) AndAlso
    (ComboBox2.SelectedItems.Count > 0) AndAlso
    (DateTime.TryParse(expiry.Text, expiry) Then

    '... do stuff
Else
    MessageBox.Show(...error message...)
End If

См. Также Класс DataTable .


Пути объектов / Вложенные

(ComboBox5.SelectedItem IsNot Nothing) AndAlso...

Код только тестирует Itemsодновременно, Public Class Form1 Private NameBoxes = New TextBox(5) {Controls("TextBox1"), _ Controls("TextBox2"), Controls("TextBox3"), _ Controls("TextBox4"), Controls("TextBox5"), _ Controls("TextBox6")} ' same thing in a different format: Private boxList As New List(Of TextBox) From {TextBox1, TextBox2, TextBox3 ...} ' Immediate NRE: Private somevar As String = Me.Controls("TextBox1").Text и Controlsможет также быть формой. Средство , чтобы проверить всю цепочку или путь объектов по одному за раз:

Controls

somevarэто важно. Последующие тесты не будут выполняться после первого .Textусловия. Это позволяет коду безопасно «сверлить» на объект (ы) один «уровень» за раз, оценивая Form_Loadтолько после (и если) Sub Newопределено как действительное. Цепочки объектов или пути могут быть довольно длинными при кодировании сложных объектов:

Form Load

Невозможно ссылаться на что-либо «вниз по течению» nullобъекта. Это также относится к элементам управления:

Sub New

Здесь Form Loadили Documentможет быть Sub Form_Load (..._ '... Dim name As String = NameBoxes (2) .Text' NRE '...' Больше кода (который, скорее всего, не будет выполнен) '... End Sub или Public Class Form1 Private myFiles() As String = Me.OpenFileDialog1.FileName & ... Private dbcon As String = OpenFileDialog1.FileName & ";Jet Oledb..." Private studentName As String = TextBox13.Text элемент может не существовать.


Элементы управления пользовательским интерфейсом

Sub New

Помимо всего прочего, этот код не предполагает, что пользователь может не выбрать что-либо в одном или нескольких элементах управления пользовательским интерфейсом. InitializeComponentвполне может быть ' Module level declaration Private NameBoxes as TextBox() Private studentName As String ' Form Load, Form Shown or Sub New: ' ' Using the OP's approach (illegal using OPTION STRICT) NameBoxes = New TextBox() {Me.Controls("TextBox1"), Me.Controls("TestBox2"), ...) studentName = TextBox32.Text ' For simple control references , поэтому GroupBoxприведет к NRE.

средство

Проверяйте данные перед их использованием (также используйте Panelи параметры SQL):

Me.Controls

Кроме того, вы можете использовать "TeStBox2"


Визуальные базовые формы

Nothing

Это довольно распространенный способ получить NRE. В C #, в зависимости от того, как он кодируется, IDE сообщит, что Controlsне существует в текущем контексте, или «не может ссылаться на нестатический член». Итак, в какой-то степени это ситуация только с VB. Это также сложно, потому что это может привести к отказу каскада.

Таким образом, массивы и коллекции не могут быть инициализированы. Этот код инициализации будет выполняться до того, как конструктор создаст Formили Controls. В результате:

  • Списки и коллекция будут просто пустыми
  • Массив будет содержать пять элементов панели
  • ControlsНазначение приведет к немедленному ЯРДУ , потому что ничто не не имеет ' Declaration Private NameBoxes As TextBox() ' Initialization - simple and easy to read, hard to botch: NameBoxes = New TextBox() {TextBox1, TextBox2, ...) ' Initialize a List NamesList = New List(Of TextBox)({TextBox1, TextBox2, TextBox3...}) ' or NamesList = New List(Of TextBox) NamesList.AddRange({TextBox1, TextBox2, TextBox3...}) свойства

После этого ссылки на элементы массива приведут к NRE. Если вы это сделаете Private bars As New List(Of Bars) ' Declared and created Public Function BarList() As List(Of Bars) bars.Clear If someCondition Then For n As Integer = 0 to someValue bars.Add(GetBar(n)) Next n Else Exit Function End If Return bars End Function , из-за нечетной ошибки, среда IDE может не сообщать об исключении, когда это произойдет. Исключение появится позже, когда ваш код попытается использовать массив. Это «молчаливое исключение» подробно описано в этом сообщении . Для наших целей ключ заключается в том, что когда что-то катастрофическое происходит при со

Похожие вопросы