Что такое исключение NullReferenceException и как его исправить?
У меня есть некоторый код, и когда он выполняется, он бросает NullReferenceException
говоря:
В экземпляре объекта не задана ссылка на объект.
Что это значит, и что я могу сделать, чтобы исправить эту ошибку?
31 ответ
В чем причина?
Нижняя линия
Вы пытаетесь использовать то, что null
(или же Nothing
в VB.NET). Это означает, что вы либо установите его на null
или вы никогда ничего не устанавливаете.
Как и все остальное, null
проходит мимо. Если это null
в методе "А" может быть так, что метод "Б" прошел null
к методу "А".
null
может иметь разные значения:
- Переменные объекта, которые неинициализированы и, следовательно, ни на что не указывают. В этом случае, если вы обращаетесь к свойствам или методам таких объектов, это вызывает
NullReferenceException
, - Разработчик использует
null
намеренно указывать, что нет значимой доступной ценности. Обратите внимание, что в C# есть концепция обнуляемых типов данных для переменных (например, таблицы базы данных могут иметь обнуляемые поля) - вы можете назначитьnull
к ним, чтобы указать, что в нем нет значения, например,int? a = null;
где знак вопроса указывает на то, что разрешено хранить ноль в переменнойa
, Вы можете проверить это либо сif (a.HasValue) {...}
или сif (a==null) {...}
, Обнуляемые переменные, такие какa
В этом примере разрешить доступ к значению черезa.Value
явно или просто как обычноa
,
Обратите внимание, что доступ к нему черезa.Value
бросаетInvalidOperationException
вместоNullReferenceException
еслиa
являетсяnull
- вы должны сделать проверку заранее, т. е. если у вас есть другая переменная, которая может быть обнуляемойint b;
тогда вы должны делать задания, какif (a.HasValue) { b = a.Value; }
или корочеif (a != null) { b = a; }
,
В остальной части этой статьи более подробно рассматриваются ошибки, которые часто допускают многие программисты, что может привести к NullReferenceException
,
Более конкретно
Время выполнения метания NullReferenceException
всегда означает одно и то же: вы пытаетесь использовать ссылку, и ссылка не инициализируется (или была однажды инициализирована, но больше не инициализирована).
Это означает, что ссылка null
и вы не можете получить доступ к членам (таким как методы) через null
ссылка. Самый простой случай:
string foo = null;
foo.ToUpper();
Это бросит NullReferenceException
во второй строке, потому что вы не можете вызвать метод экземпляра ToUpper()
на string
ссылка, указывающая на null
,
отладка
Как вы находите источник NullReferenceException
? Помимо рассмотрения самого исключения, которое будет сгенерировано точно в том месте, где оно происходит, применяются общие правила отладки в Visual Studio: устанавливайте стратегические контрольные точки и проверяйте свои переменные, наведя указатель мыши на их имена, открывая (Быстро) Наблюдайте за окном или используя различные панели отладки, такие как Locals и Autos.
Если вы хотите узнать, где находится или не установлена ссылка, щелкните правой кнопкой мыши ее имя и выберите "Найти все ссылки". Затем вы можете установить точку останова в каждом найденном месте и запустить вашу программу с подключенным отладчиком. Каждый раз, когда отладчик прерывает такую точку останова, вам нужно определить, ожидаете ли вы, что ссылка не равна нулю, проверить переменную и убедиться, что она указывает на экземпляр, когда вы этого ожидаете.
Следуя этой программе, вы можете найти место, где экземпляр не должен быть нулевым, и почему он не установлен должным образом.
Примеры
Некоторые распространенные сценарии, в которых может быть выдано исключение:
общий
ref1.ref2.ref3.member
Если ref1 или ref2 или ref3 равны нулю, вы получите NullReferenceException
, Если вы хотите решить проблему, то выясните, какая из них равна нулю, переписав выражение в его более простой эквивалент:
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.
}
}
Если вы хотите избежать нулевой ссылки дочернего (Person), вы можете инициализировать ее в конструкторе родительского (Book) объекта.
Инициализаторы вложенных объектов
То же самое относится и к инициализаторам вложенных объектов:
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; }
}
Инициализаторы вложенных коллекций ведут себя одинаково:
Person p1 = new Person {
Books = {
new Book { Title = "Title1" },
new Book { Title = "Title2" },
}
};
Это переводится как
Person p1 = new Person();
p1.Books.Add(new Book { Title = "Title1" });
p1.Books.Add(new Book { Title = "Title2" });
new Person
только создает экземпляр Person
, но Books
коллекция еще null
, Синтаксис инициализатора коллекции не создает коллекцию для 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 = agesForNames["Bob"]; // agesForNames is null.
// There is no Dictionary to perform the lookup.
Переменная диапазона (косвенная / отложенная)
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.
События
public class Demo
{
public event EventHandler StateChanged;
protected virtual void OnStateChanged(EventArgs e)
{
StateChanged(this, e); // Exception is thrown here
// if no event handlers have been attached
// to StateChanged event
}
}
Соглашения о плохом именовании:
Если вы назвали поля не так, как местные, вы могли бы понять, что никогда не инициализировали поле.
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);
}
}
Эту проблему можно решить, следуя соглашению о добавлении префикса к полям с подчеркиванием:
private Customer _customer;
Жизненный цикл страницы ASP.NET:
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!";
}
}
Значения сессии ASP.NET
// if the "FirstName" session value has not yet been set,
// then this line will throw a NullReferenceException
string firstName = Session["FirstName"].ToString();
ASP.NET MVC модели пустого представления
Если исключение возникает при ссылке на свойство @Model
в представлении ASP.NET MVC необходимо понимать, что 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 -->
Порядок и события создания элемента управления WPF
Элементы управления WPF создаются во время вызова InitializeComponent
в порядке их появления в визуальном дереве. NullReferenceException
будет вызываться в случае ранее созданных элементов управления с обработчиками событий и т. д., которые срабатывают во время 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
пытается сослаться на `label1, он еще не был создан.
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
label1.Content = comboBox1.SelectedIndex.ToString(); // NullReference here!!
}
Изменение порядка объявлений в XAML (т. Е. Листинга label1
до comboBox1
игнорируя вопросы философии дизайна, по крайней мере, NullReferenceException
Вот.
В ролях с as
var myThing = someObject as Thing;
Это не вызывает InvalidCastException, но возвращает null
когда приведение не удается (и когда someObject сам по себе равен нулю). Так что знайте об этом.
LINQ FirstOrDefault () и SingleOrDefault()
Простые версии First()
а также Single()
бросать исключения, когда ничего нет. Версии "OrDefault" в этом случае возвращают ноль. Так что знайте об этом.
для каждого
foreach
бросает при попытке перебрать нулевую коллекцию. Обычно вызвано неожиданным null
результат от методов, которые возвращают коллекции.
List<int> list = null;
foreach(var v in list) { } // exception
Более реалистичный пример - выберите узлы из XML-документа. Выдает, если узлы не найдены, но начальная отладка показывает, что все свойства действительны:
foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))
Способов избежать
Явно проверить для null
и игнорировать нулевые значения.
Если вы ожидаете, что ссылка иногда будет нулевой, вы можете проверить ее null
перед доступом к членам экземпляра:
void PrintName(Person p) {
if (p != null) {
Console.WriteLine(p.Name);
}
}
Явно проверить для null
и укажите значение по умолчанию.
Вызов методов, которые вы ожидаете вернуть, экземпляр может вернуть null
Например, когда искомый объект не может быть найден. Вы можете вернуть значение по умолчанию, если это так:
string GetCategory(Book b) {
if (b == null)
return "Unknown";
return b.Category;
}
Явно проверить для null
из вызовов методов и выбросить пользовательское исключение.
Вы также можете выдать пользовательское исключение, только чтобы перехватить его в вызывающем коде:
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
если значение никогда не должно быть null
, чтобы поймать проблему раньше, чем возникает исключение.
Когда во время разработки вы знаете, что метод может, но никогда не должен возвращаться null
, ты можешь использовать Debug.Assert()
сломаться как можно скорее, когда это произойдет:
string GetTitle(int knownBookID) {
// You know this should never return null.
var book = library.GetBook(knownBookID);
// Exception will occur on the next line instead of at the end of this method.
Debug.Assert(book != null, "Library didn't return a book for known book ID.");
// Some other code
return book.Title; // Will never throw NullReferenceException in Debug mode.
}
Хотя эта проверка не закончится в вашей сборке релиза, что вызовет NullReferenceException
снова когда book == 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
Используйте оператор объединения нулей: ??
[C#] или If()
[VB].
Сокращение для предоставления значения по умолчанию, когда null
встречается:
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;
}
Используйте нулевой оператор условия: ?.
или же ?[x]
для массивов (доступно в C# 6 и VB.NET 14):
Это также иногда называют безопасной навигацией или оператором Элвиса (после его формы). Если выражение в левой части оператора является нулевым, то правая часть не будет вычисляться, и вместо этого будет возвращено нулевое значение. Это означает, что такие случаи:
var title = person.Title.ToUpper();
Если у человека нет названия, это вызовет исключение, потому что он пытается вызвать ToUpper
на свойство с нулевым значением.
В C# 5 и ниже это может быть защищено с помощью:
var title = person.Title == null ? null : person.Title.ToUpper();
Теперь переменная title будет иметь значение null вместо исключения. C# 6 вводит более короткий синтаксис для этого:
var title = person.Title?.ToUpper();
Это приведет к тому, что переменная заголовка будет null
и призыв к ToUpper
не сделано, если person.Title
является null
,
Конечно, вам еще нужно проверить title
для нуля или используйте оператор условия null вместе с оператором объединения нулей (??
) предоставить значение по умолчанию:
// 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;
Аналогично, для массивов вы можете использовать ?[i]
следующее:
int[] myIntArray=null;
var i=5;
int? elem = myIntArray?[i];
if (!elem.HasValue) Console.WriteLine("No value");
Это будет делать следующее: если myIntArray имеет значение null, выражение возвращает значение null, и вы можете безопасно проверить его. Если он содержит массив, он будет делать то же самое, что и: elem = myIntArray[i];
и возвращает i- й элемент.
Специальные методы отладки и исправления нулевых разыменований в итераторах
C# поддерживает "блоки итераторов" (называемые "генераторами" в некоторых других популярных языках). Исключения нулевого разыменования могут быть особенно сложными для отладки в блоках итератора из-за отложенного выполнения:
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
затем 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();
}
То есть, создайте частный вспомогательный метод, который имеет блочную логику итератора, и метод открытой поверхности, который выполняет нулевую проверку и возвращает итератор. Теперь когда GetFrobs
вызывается, проверка на ноль происходит немедленно, а затем GetFrobsForReal
выполняется, когда последовательность повторяется.
Если вы изучите источник ссылки для LINQ to Objects, вы увидите, что этот метод используется повсюду. Это немного более неуклюже, чтобы написать, но это делает отладку ошибок ничтожности намного легче. Оптимизируйте свой код для удобства звонящего, а не для удобства автора.
Примечание о нулевых разыменованиях в небезопасном коде
C# имеет "небезопасный" режим, который, как следует из названия, чрезвычайно опасен, потому что обычные механизмы безопасности, которые обеспечивают безопасность памяти и безопасность типов, не применяются. Вы не должны писать небезопасный код, если у вас нет глубокого и глубокого понимания того, как работает память.
В небезопасном режиме вы должны знать о двух важных фактах:
- разыменование нулевого указателя приводит к тому же исключению, что и разыменование нулевой ссылки
- разыменование недопустимого ненулевого указателя может вызвать это исключение в некоторых обстоятельствах
Чтобы понять, почему это так, полезно понять, как.NET в первую очередь создает исключения с нулевым разыменованием. (Эти сведения относятся к.NET, работающему в Windows; другие операционные системы используют аналогичные механизмы.)
Память виртуализирована в Windows; каждый процесс получает пространство виртуальной памяти из множества "страниц" памяти, которые отслеживаются операционной системой. На каждой странице памяти установлены флаги, которые определяют, как ее можно использовать: чтение, запись, выполнение и т. Д. Самая нижняя страница помечена как "выдает ошибку, если когда-либо использовалась каким-либо образом".
И нулевой указатель, и нулевая ссылка в C# внутренне представлены как нулевое число, и поэтому любая попытка разыменовать его в соответствующее хранилище памяти приводит к ошибке операционной системы. Затем среда выполнения.NET обнаруживает эту ошибку и превращает ее в исключение нулевой разыменования.
Вот почему разыменование как нулевого указателя, так и нулевой ссылки приводит к одному и тому же исключению.
Как насчет второго пункта? Разыменование любого недопустимого указателя, который попадает на самую нижнюю страницу виртуальной памяти, вызывает ту же ошибку операционной системы и, следовательно, то же исключение.
Почему это имеет смысл? Хорошо, предположим, у нас есть структура, содержащая два целых числа и неуправляемый указатель, равный нулю. Если мы попытаемся разыменовать второе int в структуре, CLR не будет пытаться получить доступ к хранилищу в нулевом местоположении; он получит доступ к хранилищу в расположении четыре. Но логически это нулевая разыменование, потому что мы получаем по этому адресу через нуль.
Если вы работаете с небезопасным кодом и получаете исключение нулевой разыменования, просто имейте в виду, что указатель-нарушитель не обязательно должен быть нулевым. Это может быть любое место на самой нижней странице, и будет сделано это исключение.
Исключение NullReference - Visual Basic
NullReference Exception
для Visual Basic ничем не отличается от того, что в C#. В конце концов, они оба сообщают об одном и том же исключении, определенном в.NET Framework, которое они оба используют. Причины, уникальные для Visual Basic, встречаются редко (возможно, только одна).
В этом ответе будут использоваться термины, синтаксис и контекст Visual Basic. Используемые примеры взяты из большого количества прошлых вопросов о переполнении стека. Это делается для максимизации релевантности с помощью тех ситуаций, которые часто встречаются в сообщениях. Немного больше объяснений также предоставляется тем, кому это может понадобиться. Пример, похожий на ваш, очень вероятно, приведен здесь.
Замечания:
- Это основано на концепции: нет кода для вставки в ваш проект. Он предназначен, чтобы помочь вам понять, что вызывает
NullReferenceException
(NRE), как найти это, как исправить это, и как избежать этого. NRE может быть вызвано многими способами, так что вряд ли это будет ваша единственная встреча. - Примеры (из сообщений Stack Overflow) не всегда показывают лучший способ сделать что-либо в первую очередь.
- Как правило, самое простое средство используется.
Основное значение
Сообщение "Объект не установлен в экземпляр объекта" означает, что вы пытаетесь использовать объект, который не был инициализирован. Это сводится к одному из них:
- Ваш код объявил переменную объекта, но он не инициализировал ее (создайте экземпляр или создайте его экземпляр)
- То, что ваш код предполагал инициализировать объект, не сделал
- Возможно, другой код преждевременно лишил законной силы объект, все еще используемый
В поисках причины
Поскольку проблема заключается в ссылке на объект, который Nothing
, ответ заключается в том, чтобы изучить их, чтобы выяснить, какой из них. Затем определите, почему он не инициализирован. Наведите указатель мыши на различные переменные, и Visual Studio (VS) покажет их значения - виновник будет Nothing
,
Вы также должны удалить все блоки Try/Catch из соответствующего кода, особенно те, в которых нет ничего в блоке Catch. Это приведет к сбою вашего кода при попытке использовать объект, который Nothing
, Это то, что вы хотите, потому что он будет определять точное местоположение проблемы и позволит вам определить объект, вызывающий ее.
MsgBox
в улове, который отображает Error while...
будет мало помощи Этот метод также приводит к очень плохим вопросам переполнения стека, потому что вы не можете описать фактическое исключение, задействованный объект или даже строку кода, где это происходит.
Вы также можете использовать Locals Window
(Отладка -> Windows -> Локальные), чтобы проверить ваши объекты.
После того, как вы знаете, в чем и где проблема, ее обычно довольно легко исправить и быстрее, чем опубликовать новый вопрос.
Смотрите также:
- Контрольные точки
- MSDN: Как: использовать блок Try/Catch для перехвата исключений
- MSDN: лучшие практики для исключений
Примеры и средства правовой защиты
Объекты класса / Создание экземпляра
Dim reg As CashRegister
...
TextBox1.Text = reg.Amount ' NRE
Проблема в том, что Dim
не создает объект CashRegister; он только объявляет переменную с именем reg
этого типа. Объявление переменной объекта и создание экземпляра - это две разные вещи.
средство
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
снова в процедуре, включая конструктор (Sub New
):
Private reg As CashRegister
'...
Public Sub New()
'...
Dim reg As New CashRegister
End Sub
Это создаст локальную переменную, reg
, который существует только в этом контексте (подпункт). reg
переменная с уровнем модуля Scope
который вы будете использовать везде, где еще остается Nothing
,
Отсутствует
New
Оператор является причиной № 1NullReference Exceptions
рассматривается в рассмотренных вопросах переполнения стека.Visual Basic пытается прояснить процесс несколько раз, используя
New
: С использованиемNew
Оператор создает новый объект и вызываетSub New
- конструктор - где ваш объект может выполнить любую другую инициализацию.
Чтобы быть понятным, Dim
(или же Private
) только объявляет переменную и ее Type
, Область действия переменной - существует ли она для всего модуля / класса или является локальной для процедуры - определяется тем, где она объявлена. Private | Friend | Public
определяет уровень доступа, а не Scope.
Для получения дополнительной информации см.:
- Новый оператор
- Область применения в Visual Basic
- Уровни доступа в Visual Basic
- Типы значений и ссылочные типы
Массивы
Массивы также должны быть созданы:
Private arr as String()
Этот массив только объявлен, но не создан. Существует несколько способов инициализации массива:
Private arr as String() = New String(10){}
' or
Private arr() As String = New String(10){}
' For a local array (in a procedure) and using 'Option Infer':
Dim arr = New String(10) {}
Примечание. Начиная с VS 2010, при инициализации локального массива с использованием литерала и Option Infer
, As <Type>
а также New
элементы являются необязательными:
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>
с Option 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
Массив был создан, но Foo
объектов в нем нет.
средство
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
Для получения дополнительной информации см.:
Списки и Коллекции
Коллекции.NET (которых существует множество разновидностей - списки, словарь и т. Д.) Также должны быть созданы или созданы.
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
Любая процедура приведет к NRE, потому что barList
объявляется, а не создается. Создание экземпляра Foo
также не будет создавать экземпляр внутреннего barList
, Возможно, это было сделано в конструкторе:
Public Sub New ' Constructor
' Stuff to do when a new Foo is created...
barList = New List(Of Bar)
End Sub
Как и раньше, это неверно:
Public Sub New()
' Creates another barList local to this procedure
Dim barList As New List(Of Bar)
End Sub
Для получения дополнительной информации см. List(Of T)
Класс
Объекты провайдера данных
Работа с базами данных предоставляет много возможностей для NullReference, потому что может быть много объектов (Command
, Connection
, Transaction
, Dataset
, DataTable
, DataRows
....) используется сразу. Примечание. Неважно, какой поставщик данных вы используете - MySQL, SQL Server, OleDB и т. Д. - концепции совпадают.
Пример 1
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
является локальной переменной, IDE предупреждает вас, что это может произойти:
Когда объявляется как переменная уровня модуля / класса, как кажется, имеет место с con
компилятор не может знать, был ли объект создан с помощью вышестоящей процедуры. Не игнорируйте предупреждения.
средство
Dim ds As New DataSet
Пример 2
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
против Employee
, Не было DataTable
с именем "Сотрудник" создан, поэтому NullReferenceException
результаты пытаются получить к нему доступ. Другая потенциальная проблема предполагает, что будет Items
что может быть не так, когда SQL включает предложение WHERE.
средство
Поскольку это использует одну таблицу, используя 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...
Пример 3
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
как показано в предыдущем примере, но он не анализирует имена из таблицы SQL или базы данных. В следствии, ds.Tables("TICKET_RESERVATION")
ссылается на несуществующую таблицу.
Средство не изменилось, обратитесь к таблице по индексу:
If ds.Tables(0).Rows.Count > 0 Then
Смотрите также DataTable Class.
Пути к объектам / вложенные
If myFoo.Bar.Items IsNot Nothing Then
...
Код только тестирование Items
в то время как оба myFoo
а также Bar
Также может быть ничего. Средство защиты состоит в том, чтобы проверять всю цепочку или путь объектов по одному:
If (myFoo IsNot Nothing) AndAlso
(myFoo.Bar IsNot Nothing) AndAlso
(myFoo.Bar.Items IsNot Nothing) Then
....
AndAlso
это важно. Последующие тесты не будут выполнены после первого False
условие встречено. Это позволяет коду безопасно "углубляться" в объект (ы) по одному "уровню" за раз, оценивая myFoo.Bar
только после (и если) myFoo
определяется как действительный. Цепочки объектов или пути могут быть довольно длинными при кодировании сложных объектов:
myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename")
Невозможно сослаться на что-либо "вниз по течению" null
объект. Это также относится к элементам управления:
myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"
Вот, myWebBrowser
или же Document
Ничего не может быть или formfld1
элемент может не существовать
UI Controls
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)
Среди прочего, этот код не предполагает, что пользователь, возможно, не выбрал что-то в одном или нескольких элементах управления пользовательского интерфейса. ListBox1.SelectedItem
вполне может быть Nothing
, так ListBox1.SelectedItem.ToString
приведет к NRE.
средство
Проверьте данные перед использованием (также используйте Option Strict
и параметры SQL):
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
Кроме того, вы можете использовать (ComboBox5.SelectedItem IsNot Nothing) AndAlso...
Visual Basic Forms
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
Это довольно распространенный способ получить NRE. В C#, в зависимости от того, как это закодировано, IDE сообщит, что Controls
не существует в текущем контексте или "не может ссылаться на нестатический член". Так что, в некоторой степени, это ситуация только для VB. Это также сложно, потому что это может привести к каскаду сбоев.
Массивы и коллекции не могут быть инициализированы таким образом. Этот код инициализации будет запущен до того, как конструктор создаст Form
или Controls
, В следствии:
- Списки и Коллекция будут просто пустыми
- Массив будет содержать пять элементов Nothing
-
somevar
назначение приведет к немедленному NRE, потому что ничто не имеет.Text
имущество
Ссылка на элементы массива позже приведет к NRE. Если вы делаете это в Form_Load
, из-за странной ошибки, IDE может не сообщать об исключении, когда это происходит. Исключение появится позже, когда ваш код попытается использовать массив. Это "тихое исключение" подробно описано в этом посте. Для наших целей ключ заключается в том, что когда происходит что-то катастрофическое при создании формы (Sub New
или же Form Load
событие), исключения могут остаться незамеченными, код выходит из процедуры и просто отображает форму.
Так как нет другого кода в вашем Sub New
или же Form Load
событие будет проходить после NRE, многие другие вещи можно оставить неинициализированными.
Sub Form_Load(..._
'...
Dim name As String = NameBoxes(2).Text ' NRE
' ...
' More code (which will likely not be executed)
' ...
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
Частичное Средство
Любопытно, что VB не выдает предупреждение, но исправление состоит в том, чтобы объявить контейнеры на уровне формы, но инициализировать их в обработчике события загрузки формы, когда элементы управления существуют. Это можно сделать в 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
или же Panel
) не будет найден в Me.Controls
; они будут в коллекции Controls этой Panel или GroupBox. Также не будет возвращен элемент управления, если имя элемента управления написано с ошибкой ("TeStBox2"
). В таких случаях, Nothing
будет снова сохранен в этих элементах массива, и при попытке обратиться к нему будет получено NRE.
Теперь их легко найти, когда вы знаете, что ищете:
"Button2" находится на Panel
средство
Вместо косвенных ссылок по имени, используя форму 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...})
Функция ничего не возвращает
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 предупредит вас, что " не все пути возвращают значение и NullReferenceException
может привести ". Вы можете подавить предупреждение, заменив Exit Function
с Return Nothing
, но это не решает проблему. Все, что пытается использовать возврат, когда someCondition = False
приведет к NRE:
bList = myFoo.BarList()
For Each b As Bar in bList ' EXCEPTION
...
средство
замещать Exit Function
в функции с Return bList
, Возвращение пустого List
это не то же самое, что возвращение Nothing
, Если есть вероятность, что возвращенный объект может быть Nothing
протестируйте перед использованием:
bList = myFoo.BarList()
If bList IsNot Nothing Then...
Плохо реализовано Try/Catch
Плохо реализованный Try/Catch может скрыть, где проблема, и привести к новым:
Dim dr As SqlDataReader
Try
Dim lnk As LinkButton = TryCast(sender, LinkButton)
Dim gr As GridViewRow = DirectCast(lnk.NamingContainer, GridViewRow)
Dim eid As String = GridView1.DataKeys(gr.RowIndex).Value.ToString()
ViewState("username") = eid
sqlQry = "select FirstName, Surname, DepartmentName, ExtensionName, jobTitle,
Pager, mailaddress, from employees1 where username='" & eid & "'"
If connection.State <> ConnectionState.Open Then
connection.Open()
End If
command = New SqlCommand(sqlQry, connection)
'More code fooing and barring
dr = command.ExecuteReader()
If dr.Read() Then
lblFirstName.Text = Convert.ToString(dr("FirstName"))
...
End If
mpe.Show()
Catch
Finally
command.Dispose()
dr.Close() ' <-- NRE
connection.Close()
End Try
Это случай, когда объект создается не так, как ожидалось, но также демонстрирует полезность счетчика пустого Catch
,
В SQL есть дополнительная запятая (после 'mailaddress'), что приводит к исключению в .ExecuteReader
, После Catch
ничего не делает, Finally
пытается выполнить очистку, но так как вы не можете Close
ноль DataReader
объект, новый NullReferenceException
Результаты.
Пустой Catch
Блок - игровая площадка дьявола. Этот ОП был сбит с толку, почему он получил NRE в Finally
блок. В других ситуациях пустой Catch
Это может привести к тому, что что-то гораздо более низкое по течению станет бесполезным и приведет к тому, что вы потратите время на поиск неправильных вещей в неправильном месте проблемы. (Описанное выше "тихое исключение" обеспечивает ту же развлекательную ценность.)
средство
Не используйте пустые блоки Try/Catch - позвольте крушению кода, чтобы вы могли a) определить причину b) определить местоположение и c) применить надлежащее решение. Блоки Try/Catch не предназначены для сокрытия исключений от лица, обладающего уникальной квалификацией для их устранения - разработчика.
DBNull не то же самое, что Nothing
For Each row As DataGridViewRow In dgvPlanning.Rows
If Not IsDBNull(row.Cells(0).Value) Then
...
IsDBNull
Функция используется для проверки, если значение равно System.DBNull
: Из MSDN:
Значение System.DBNull указывает, что объект представляет отсутствующие или несуществующие данные. DBNull отличается от Nothing, что указывает на то, что переменная еще не инициализирована.
средство
If row.Cells(0) IsNot Nothing Then ...
Как и раньше, вы можете проверить на Ничто, а затем для конкретного значения:
If (row.Cells(0) IsNot Nothing) AndAlso (IsDBNull(row.Cells(0).Value) = False) Then
Пример 2
Dim getFoo = (From f In dbContext.FooBars
Where f.something = something
Select f).FirstOrDefault
If Not IsDBNull(getFoo) Then
If IsDBNull(getFoo.user_id) Then
txtFirst.Text = getFoo.first_name
Else
...
FirstOrDefault
возвращает первый элемент или значение по умолчанию, которое Nothing
для справочных типов и никогда DBNull
:
If getFoo IsNot Nothing Then...
управления
Dim chk As CheckBox
chk = CType(Me.Controls(chkName), CheckBox)
If chk.Checked Then
Return chk
End If
Если CheckBox
с chkName
не может быть найден (или существует в GroupBox
), затем chk
Ничего не будет, и попытка ссылки на какое-либо свойство приведет к исключению.
средство
If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...
DataGridView
У DGV есть несколько причуд, периодически замечаемых:
dgvBooks.DataSource = loan.Books
dgvBooks.Columns("ISBN").Visible = True ' NullReferenceException
dgvBooks.Columns("Title").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Author").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Price").DefaultCellStyle.Format = "C"
Если dgvBooks
имеет AutoGenerateColumns = True
, он создает столбцы, но не называет их, поэтому приведенный выше код завершается ошибкой, когда ссылается на них по имени.
средство
Назовите столбцы вручную или используйте указатель по индексу:
dgvBooks.Columns(0).Visible = True
Пример 2 - Остерегайтесь NewRow
xlWorkSheet = xlWorkBook.Sheets("sheet1")
For i = 0 To myDGV.RowCount - 1
For j = 0 To myDGV.ColumnCount - 1
For k As Integer = 1 To myDGV.Columns.Count
xlWorkSheet.Cells(1, k) = myDGV.Columns(k - 1).HeaderText
xlWorkSheet.Cells(i + 2, j + 1) = myDGV(j, i).Value.ToString()
Next
Next
Next
Когда ваш DataGridView
имеет AllowUserToAddRows
как True
(по умолчанию), Cells
в пустой / новой строке внизу все будет содержать Nothing
, Большинство попыток использовать содержимое (например, ToString
) приведет к NRE.
средство
Использовать For/Each
зациклить и проверить IsNewRow
свойство, чтобы определить, является ли это той последней строкой. Это работает ли AllowUserToAddRows
верно или нет:
For Each r As DataGridViewRow in myDGV.Rows
If r.IsNewRow = False Then
' ok to use this row
Если вы используете For n
цикл, изменить количество строк или использовать Exit For
когда IsNewRow
правда.
My.Settings (StringCollection)
При определенных обстоятельствах, пытаясь использовать предмет из My.Settings
который является StringCollection
может привести к NullReference при первом использовании. Решение то же самое, но не так очевидно. Рассматривать:
My.Settings.FooBars.Add("ziggy") ' foobars is a string collection
Поскольку VB управляет настройками для вас, разумно ожидать, что он инициализирует коллекцию. Это произойдет, но только если вы ранее добавили первоначальную запись в коллекцию (в редакторе настроек). Поскольку коллекция (по-видимому) инициализируется при добавлении элемента, она остается Nothing
когда в редакторе настроек нет элементов для добавления.
средство
Инициализируйте коллекцию настроек в форме Load
обработчик события, если / когда необходимо:
If My.Settings.FooBars Is Nothing Then
My.Settings.FooBars = New System.Collections.Specialized.StringCollection
End If
Как правило, Settings
коллекция должна быть инициализирована только при первом запуске приложения. Альтернативное решение - добавить начальное значение к вашей коллекции в Project -> Settings | FooBars, сохраните проект, затем удалите поддельное значение.
Ключевые моменты
Вы, наверное, забыли New
оператор.
или же
То, что вы предполагали, будет работать безупречно, чтобы вернуть инициализированный объект в ваш код, не так.
Не игнорируйте предупреждения компилятора (никогда) и используйте Option Strict On
(всегда).
Другой сценарий - когда вы приводите нулевой объект в тип значения. Например, код ниже:
object o = null;
DateTime d = (DateTime)o;
Это бросит NullReferenceException
на актерский состав. Это кажется вполне очевидным в приведенном выше примере, но это может произойти в более сложных запоздалых сценариях, когда нулевой объект был возвращен из некоторого кода, который вам не принадлежит, и приведение, например, генерируется некоторой автоматической системой.
Одним из примеров этого является этот простой фрагмент привязки ASP.NET с элементом управления Calendar:
<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />
Вот, SelectedDate
на самом деле является собственностью DateTime
тип - из Calendar
Тип Web Control, и привязка может отлично вернуть что-то нулевое. Неявный ASP.NET Generator создаст фрагмент кода, который будет эквивалентен приведенному выше коду. И это поднимет NullReferenceException
это довольно трудно обнаружить, потому что он лежит в сгенерированном ASP.NET коде, который прекрасно компилируется
Это означает, что ваш код использовал переменную ссылки на объект, для которой было установлено значение null (то есть он не ссылался на фактический экземпляр объекта).
Чтобы предотвратить ошибку, объекты, которые могут быть нулевыми, должны быть проверены на нулевое значение перед использованием.
if (myvar != null)
{
// Go ahead and use myvar
myvar.property = ...
}
else
{
// Whoops! myvar is null and cannot be used without first
// assigning it to an instance reference
// Attempting to use myvar here will result in NullReferenceException
}
Это означает, что рассматриваемая переменная ни на что не указана. Я мог бы сгенерировать это так:
SqlConnection connection = null;
connection.Open();
Это выдаст ошибку, потому что пока я объявил переменнуюconnection
"Это ни на что не указывает. Когда я пытаюсь позвонить участнику"Open
msgstr "нет ссылки для разрешения, и это вызовет ошибку.
Чтобы избежать этой ошибки:
- Всегда инициализируйте ваши объекты, прежде чем пытаться что-либо с ними делать.
- Если вы не уверены, является ли объект нулевым, проверьте его с помощью
object == null
,
Инструмент JetBrains Resharper будет идентифицировать каждое место в вашем коде, в котором может быть ошибка нулевой ссылки, что позволяет вам поставить нулевую проверку. Эта ошибка - источник ошибок номер один, ИМХО.
Имейте в виду, что независимо от сценария причина всегда одинакова в.NET:
Вы пытаетесь использовать ссылочную переменную, значение которой равно
Nothing
/null
, Когда значениеNothing
/null
для ссылочной переменной это означает, что она фактически не содержит ссылку на экземпляр какого-либо объекта, который существует в куче.Вы либо никогда не присваивали что-либо переменной, ни разу не создавали экземпляр значения, присвоенного переменной, или устанавливали переменную равной
Nothing
/null
вручную, или вы вызвали функцию, которая устанавливает переменную вNothing
/null
для тебя.
Пример этого исключения: Когда вы пытаетесь что-то проверить, это пустое значение.
Например:
string testString = null; //Because it doesn't have a value (i.e. it's null; "Length" cannot do what it needs to do)
if (testString.Length == 0) // Throws a nullreferenceexception
{
//Do something
}
Среда выполнения.NET генерирует исключение NullReferenceException при попытке выполнить действие с чем-то, что не было создано, например с кодом выше.
По сравнению с ArgumentNullException, который обычно генерируется как защитная мера, если метод ожидает, что то, что ему передается, не равно нулю.
Больше информации в C# NullReferenceException и Null Parameter.
Если вы не инициализировали ссылочный тип и хотите установить или прочитать одно из его свойств, оно выдаст исключение NullReferenceException.
Пример:
Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.
Вы можете просто избежать этого, проверив, не является ли переменная нулевой:
Person p = null;
if (p!=null)
{
p.Name = "Harry"; // Not going to run to this point
}
Чтобы полностью понять, почему выбрасывается исключение NullReferenceException, важно знать разницу между типами значений и ссылочными типами.
Таким образом, если вы имеете дело с типами значений, NullReferenceExceptions не может возникнуть. Хотя при работе с ссылочными типами нужно соблюдать бдительность!
Только ссылочные типы, как следует из названия, могут содержать ссылки или указывать буквально на ничто (или "ноль"). В то время как типы значений всегда содержат значение.
Типы ссылок (эти должны быть проверены):
- динамический
- объект
- строка
Типы значений (вы можете просто игнорировать эти):
- Числовые типы
- Интегральные типы
- Типы с плавающей точкой
- десятичный
- BOOL
- Пользовательские структуры
Еще один случай, когда NullReferenceExceptions
может произойти (неправильное) использование as
оператор:
class Book {
public string Name { get; set; }
}
class Car { }
Car mycar = new Car();
Book mybook = mycar as Book; // Incompatible conversion --> mybook = null
Console.WriteLine(mybook.Name); // NullReferenceException
Вот, Book
а также Car
несовместимые типы; Car
не может быть преобразован / приведен к Book
, Когда этот бросок не удался, as
возвращается null
, С помощью mybook
после этого вызывает NullReferenceException
,
В общем, вы должны использовать бросок или as
, следующее:
Если вы ожидаете, что преобразование типов будет всегда успешным (т.е. вы знаете, какой объект должен быть раньше времени), тогда вам следует использовать приведение:
ComicBook cb = (ComicBook)specificBook;
Если вы не уверены в типе, но хотите попробовать использовать его как определенный тип, используйте as
:
ComicBook cb = specificBook as ComicBook;
if (cb != null) {
// ...
}
Вы используете объект, который содержит ссылку на нулевое значение. Так что это дает нулевое исключение. В этом примере строковое значение равно нулю, и при проверке его длины произошло исключение.
Пример:
string value = null;
if (value.Length == 0) // <-- Causes exception
{
Console.WriteLine(value); // <-- Never reached
}
Ошибка исключения:
Необработанное исключение:
System.NullReferenceException: ссылка на объект не установлена на экземпляр объекта. в Program.Main()
В то время как то, что вызывает исключения NullReferenceException и подходы, чтобыизбежать / исправить такое исключение, было рассмотрено в других ответах, многие программисты еще не узнали, как самостоятельно отлаживать такие исключения во время разработки.
В Visual Studio это обычно легко благодаря отладчику Visual Studio.
Во-первых, убедитесь, что будет обнаружена правильная ошибка - см. Как разрешить разрыв на System.NullReferenceException в VS2010?Примечание1
Затем либо начните с отладки (F5), либо присоедините [отладчик VS] к запущенному процессу. Иногда может быть полезно использоватьDebugger.Break
, который предложит запустить отладчик.
Теперь, когда NullReferenceException генерируется (или не обрабатывается), отладчик останавливается (помните, как установлено выше?) На строке, в которой произошло исключение. Иногда ошибку легко заметить.
Например, в следующей строке единственный код, который может вызвать исключение, это еслиmyString
оценивается как ноль. Это можно проверить, посмотрев в окно просмотра или запустив выражения в Immediate Window.
var x = myString.Trim();
В более сложных случаях, таких как следующие, вам нужно использовать один из методов, описанных выше (Watch или Immediate Windows), чтобы проверить выражения, чтобы определить,str1
был нулевым или еслиstr2
был нулевым
var x = str1.Trim() + str2.Trim();
После того, как было найдено исключение throw, обычно тривиально рассуждать в обратном направлении, чтобы выяснить, где [неправильно] было введено нулевое значение -
Потратьте время, необходимое для понимания причины исключения. Осмотрите для нулевых выражений. Проверьте предыдущие выражения, которые могли привести к таким нулевым выражениям. Добавьте точки останова и пошагово пройдитесь по программе. Используйте отладчик.
1 Если Break on Throws слишком агрессивен и отладчик останавливается на NPE в.NET или сторонней библиотеке, можно использовать Break on User-Unhandled для ограничения перехвата исключений. Кроме того, VS2012 представляет Just My Code, который я также рекомендую включить.
Если вы выполняете отладку с включенным Just My Code, поведение будет немного другим. При включенном Just My Code отладчик игнорирует исключительные ситуации общеязыковой среды выполнения (CLR), которые выдаются за пределами My Code и не проходят через My Code
Саймон Мурье привел этот пример:
object o = null;
DateTime d = (DateTime)o; // NullReferenceException
где конвертация распаковки (каст) из object
(или из одного из классов System.ValueType
или же System.Enum
или от типа интерфейса) к типу значения (кроме Nullable<>
) сама по себе дает NullReferenceException
,
В другом направлении, бокс преобразование из Nullable<>
у которого есть HasValue
равно false
к ссылочному типу, может дать null
ссылка, которая затем может привести к NullReferenceException
, Классический пример:
DateTime? d = null;
var s = d.ToString(); // OK, no exception (no boxing), returns ""
var t = d.GetType(); // Bang! d is boxed, NullReferenceException
Иногда бокс бывает по-другому. Например, с помощью этого неуниверсального метода расширения:
public static void MyExtension(this object x)
{
x.ToString();
}
следующий код будет проблематичным:
DateTime? d = null;
d.MyExtension(); // Leads to boxing, NullReferenceException occurs inside the body of the called method, not here.
Эти случаи возникают из-за специальных правил, которые среда выполнения использует при упаковке Nullable<>
экземпляров.
Добавление случая, когда имя класса для сущности, используемой в платформе сущностей, совпадает с именем класса для файла кода веб-формы.
Предположим, у вас есть веб-форма Contact.aspx с классом codebehind - "Контакт", и у вас есть имя сущности "Контакт".
Затем следующий код вызовет исключение NullReferenceException при вызове context.SaveChanges()
Contact contact = new Contact { Name = "Abhinav"};
var context = new DataContext();
context.Contacts.Add(contact);
context.SaveChanges(); // NullReferenceException at this line
Ради полноты класса DataContext
public class DataContext : DbContext
{
public DbSet<Contact> Contacts {get; set;}
}
и Связаться с объектом класса. Иногда классы сущностей являются частичными классами, так что вы можете расширять их и в других файлах.
public partial class Contact
{
public string Name {get; set;}
}
Ошибка возникает, когда сущность и класс codebehind находятся в одном пространстве имен. Чтобы исправить это, переименуйте класс сущности или класс codebehind для Contact.aspx.
Причина, я все еще не уверен в причине. Но всякий раз, когда какой-либо из классов сущностей расширяет System.Web.UI.Page, возникает эта ошибка.
Для обсуждения взгляните на NullReferenceException в DbContext.saveChanges()
Другой общий случай, когда можно получить это исключение, связан с классами насмешек во время модульного тестирования Независимо от используемой среды моделирования, вы должны убедиться, что все соответствующие уровни иерархии классов должным образом смоделированы. В частности, все свойства HttpContext
на которые ссылается тестируемый код, должен быть посмешищем.
См. " NullReferenceException, генерируемое при тестировании пользовательского AuthorizationAttribute" для несколько подробного примера.
У меня другая точка зрения, чтобы ответить на это. Такого рода ответы "что еще я могу сделать, чтобы избежать этого?"
При работе на разных уровнях, например, в приложении MVC, контроллеру нужны сервисы для вызова бизнес-операций. В таких сценариях Dependency Injection Container можно использовать для инициализации служб, чтобы избежать исключения NullReferenceException. Таким образом, это означает, что вам не нужно беспокоиться о проверке на null и просто вызывать сервисы из контроллера, как если бы они всегда были доступны (и инициализированы) в виде одиночного или прототипа.
public class MyController
{
private ServiceA serviceA;
private ServiceB serviceB;
public MyController(ServiceA serviceA, ServiceB serviceB)
{
this.serviceA = serviceA;
this.serviceB = serviceB;
}
public void MyMethod()
{
// We don't need to check null because the dependency injection container
// injects it, provided you took care of bootstrapping it.
var someObject = serviceA.DoThis();
}
}
На вопрос "что мне с этим делать" может быть много ответов.
Более "формальным" способом предотвращения возникновения таких ошибок при разработке является применение проекта по контракту в вашем коде. Это означает, что вам нужно установить инварианты класса и / или даже предварительные условия и постфункции в вашей системе при разработке.
Короче говоря, инварианты класса гарантируют, что в вашем классе будут некоторые ограничения, которые не будут нарушаться при обычном использовании (и, следовательно, класс не попадет в противоречивое состояние). Предварительные условия означают, что данные, переданные в качестве входных данных для функции / метода, должны следовать некоторым установленным ограничениям и никогда не нарушать их, а постусловия означают, что выходные данные функции / метода должны снова следовать установленным ограничениям, не нарушая их. Условия контракта никогда не должны нарушаться во время выполнения безошибочной программы, поэтому проектирование по контракту проверяется на практике в режиме отладки, хотя и отключается в выпусках, чтобы максимизировать производительность разработанной системы.
Таким образом, вы можете избежать NullReferenceException
случаи, которые являются результатом нарушения установленных ограничений. Например, если вы используете свойство объекта X
в классе, а затем попробуйте вызвать один из его методов и X
имеет нулевое значение, то это приведет к NullReferenceException
:
public X { get; set; }
public void InvokeX()
{
X.DoSomething(); // if X value is null, you will get a NullReferenceException
}
Но если вы зададите "свойство X никогда не должно иметь нулевое значение" в качестве предварительного условия метода, то вы можете предотвратить описанный выше сценарий:
//Using code contracts:
[ContractInvariantMethod]
protected void ObjectInvariant ()
{
Contract.Invariant ( X != null );
//...
}
По этой причине проект Code Contracts существует для приложений.NET.
В качестве альтернативы, дизайн по контракту может применяться с использованием утверждений.
ОБНОВЛЕНИЕ: Стоит отметить, что этот термин был придуман Бертраном Мейером в связи с его разработкой языка программирования Eiffel.
NullReferenceException
генерируется, когда мы пытаемся получить доступ к свойствам нулевого объекта или когда строковое значение становится пустым, а мы пытаемся получить доступ к строковым методам.
Например:
При обращении к строковому методу пустой строки:
string str = string.Empty; str.ToLower(); // throw null reference exception
При обращении к свойству нулевого объекта:
Public Class Person { public string Name { get; set; } } Person objPerson; objPerson.Name /// throw Null refernce Exception
TL;DR: попробуйте использовать Html.Partial
вместо Renderpage
Я получал Object reference not set to an instance of an object
когда я попытался визуализировать представление в представлении, отправив ему модель, например:
@{
MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null
Отладка показала, что модель была нулевой внутри MyOtherView. Пока я не изменил это на:
@{
MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);
И это сработало.
Кроме того, причина, по которой у меня не было Html.Partial
Начать с того, что Visual Studio иногда выдает ошибочно выглядящие волнистые линии под Html.Partial
если он внутри по-другому построен foreach
цикл, хотя это не совсем ошибка:
@inherits System.Web.Mvc.WebViewPage
@{
ViewBag.Title = "Entity Index";
List<MyEntity> MyEntities = new List<MyEntity>();
MyEntities.Add(new MyEntity());
MyEntities.Add(new MyEntity());
MyEntities.Add(new MyEntity());
}
<div>
@{
foreach(var M in MyEntities)
{
// Squiggly lines below. Hovering says: cannot convert method group 'partial' to non-delegate type Object, did you intend to envoke the Method?
@Html.Partial("MyOtherView.cshtml");
}
}
</div>
Но я смог запустить приложение без проблем с этой "ошибкой". Я смог избавиться от ошибки, изменив структуру foreach
цикл, чтобы выглядеть так:
@foreach(var M in MyEntities){
...
}
Хотя у меня такое ощущение, что Visual Studio неправильно читала амперсанды и скобки.
Что вы можете с этим поделать?
Здесь есть много хороших ответов, объясняющих, что такое пустая ссылка и как ее отладить. Но есть очень мало о том, как предотвратить проблему или, по крайней мере, облегчить ее обнаружение.
Проверьте аргументы
Например, методы могут проверять различные аргументы, чтобы увидеть, являются ли они пустыми, и генерировать ArgumentNullException
Исключение, очевидно, создано именно для этой цели.
Конструктор для ArgumentNullException
даже принимает имя параметра и сообщение в качестве аргумента, чтобы вы могли точно сказать разработчику, в чем проблема.
public void DoSomething(MyObject obj) {
if(obj == null)
{
throw new ArgumentNullException("obj", "Need a reference to obj.");
}
}
Используйте инструменты
Есть также несколько библиотек, которые могут помочь. Например, "Resharper" может выдавать вам предупреждения во время написания кода, особенно если вы используете их атрибут: NotNullAttribute
Есть "Microsoft Code Contracts", где вы используете синтаксис, такой как Contract.Requires(obj != null)
который дает вам время выполнения и проверку компиляции: введение в контракты кода.
Также есть "PostSharp", который позволит вам просто использовать такие атрибуты:
public void DoSometing([NotNull] obj)
Делая это и делая PostSharp частью вашего процесса сборки obj
будет проверен на ноль во время выполнения. Смотрите: PostSharp нулевая проверка
Решение с простым кодом
Или вы всегда можете написать свой собственный подход, используя простой старый код. Например, вот структура, которую вы можете использовать для перехвата нулевых ссылок. Он смоделирован по той же концепции, что и Nullable<T>
:
[System.Diagnostics.DebuggerNonUserCode]
public struct NotNull<T> where T: class
{
private T _value;
public T Value
{
get
{
if (_value == null)
{
throw new Exception("null value not allowed");
}
return _value;
}
set
{
if (value == null)
{
throw new Exception("null value not allowed.");
}
_value = value;
}
}
public static implicit operator T(NotNull<T> notNullValue)
{
return notNullValue.Value;
}
public static implicit operator NotNull<T>(T value)
{
return new NotNull<T> { Value = value };
}
}
Вы будете использовать очень похоже на то же самое, что вы использовали бы Nullable<T>
кроме как с целью достижения прямо противоположного - не допустить null
, Вот некоторые примеры:
NotNull<Person> person = null; // throws exception
NotNull<Person> person = new Person(); // OK
NotNull<Person> person = GetPerson(); // throws exception if GetPerson() returns null
NotNull<T>
неявно приведен к и из T
так что вы можете использовать его где угодно. Например, вы можете передать Person
возражать против метода, который принимает NotNull<Person>
:
Person person = new Person { Name = "John" };
WriteName(person);
public static void WriteName(NotNull<Person> person)
{
Console.WriteLine(person.Value.Name);
}
Как вы можете видеть выше, как и для nullable, вы получите доступ к базовому значению через Value
имущество. В качестве альтернативы вы можете использовать явное или неявное приведение, вы можете увидеть пример с возвращаемым значением ниже:
Person person = GetPerson();
public static NotNull<Person> GetPerson()
{
return new Person { Name = "John" };
}
Или вы даже можете использовать его, когда метод просто возвращает T
(в этом случае Person
) выполнив актерский состав. Например, следующий код будет похож на приведенный выше код:
Person person = (NotNull<Person>)GetPerson();
public static Person GetPerson()
{
return new Person { Name = "John" };
}
Объединить с расширением
скомбинировать NotNull<T>
с методом расширения, и вы можете охватить даже больше ситуаций. Вот пример того, как может выглядеть метод расширения:
[System.Diagnostics.DebuggerNonUserCode]
public static class NotNullExtension
{
public static T NotNull<T>(this T @this) where T: class
{
if (@this == null)
{
throw new Exception("null value not allowed");
}
return @this;
}
}
И вот пример того, как это можно использовать:
var person = GetPerson().NotNull();
GitHub
Для справки, я сделал приведенный выше код доступным на GitHub, вы можете найти его по адресу:
https://github.com/luisperezphd/NotNull
Родственный язык
В C# 6.0 введен "нулевой оператор", который немного помогает в этом. С помощью этой функции вы можете ссылаться на вложенные объекты, и если любой из них null
все выражение возвращается null
,
Это уменьшает количество нулевых проверок, которые вы должны сделать в некоторых случаях. Синтаксис ставит знак вопроса перед каждой точкой. Возьмите следующий код для примера:
var address = country?.State?.County?.City;
Представь это country
является объектом типа Country
который имеет свойство под названием State
и так далее. Если country
, State
, County
, или же City
является null
затем address will be
ноль. Therefore you only have to check whether
адресis
null`.
Это отличная функция, но она дает вам меньше информации. Это не делает очевидным, какой из 4 является нулевым.
Встроенный как Nullable?
C# имеет хорошую стенографию для Nullable<T>
, вы можете сделать что-то обнуляемое, поставив знак вопроса после типа, как так int?
,
Было бы хорошо, если бы C# имел что-то вроде NotNull<T>
Структура выше и имеет аналогичные сокращения, может быть, восклицательный знак (!), чтобы вы могли написать что-то вроде: public void WriteName(Person! person)
,
Вы можете исправить NullReferenceException чистым способом с помощью Null-условных операторов в C#6 и написать меньше кода для обработки нулевых проверок.
Он используется для проверки на нулевое значение перед выполнением операции доступа к члену (?.) Или операции индекса (?[).
пример
var name = p?.Spouse?.FirstName;
эквивалентно:
if (p != null)
{
if (p.Spouse != null)
{
name = p.Spouse.FirstName;
}
}
В результате имя будет нулевым, если p равно нулю или когда p.Spouse равно нулю.
В противном случае имени переменной будет присвоено значение p.Spouse.FirstName.
Для более подробной информации: Нулевые операторы
Интересно, что ни один из ответов на этой странице не упоминает два крайних случая, надеюсь, никто не возражает, если я добавлю их:
Крайний случай № 1: одновременный доступ к словарю
Общие словари в.NET не являются поточно-ориентированными и иногда могут NullReference
или даже (чаще) KeyNotFoundException
когда вы пытаетесь получить доступ к ключу из двух параллельных потоков. Исключение весьма обманчиво в этом случае.
Крайний случай № 2: небезопасный код
Если NullReferenceException
брошен unsafe
код, вы можете посмотреть на ваши переменные указателя, и проверить их на IntPtr.Zero
или что-то. Это то же самое ("исключение нулевого указателя"), но в небезопасном коде переменные часто приводятся к типам / массивам значений и т. Д., И вы бьетесь головой о стену, задаваясь вопросом, как тип значения может бросить это исключение.
(Кстати, еще одна причина не использовать небезопасный код, если он вам не нужен)
Строка ошибки "Ссылка на объект не установлена для экземпляра объекта. " Указывает, что вы не назначили объект экземпляра для ссылки на объект, и все же вы получаете доступ к свойствам / методам этого объекта.
например: допустим, у вас есть класс с именем myClass, и он содержит одно свойство prop1.
public Class myClass
{
public int prop1 {get;set;}
}
Теперь вы получаете доступ к этому prop1 в каком-то другом классе, как показано ниже:
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref.prop1 = 1; //This line throws error
}
}
вышеприведенная строка выдает ошибку, поскольку ссылка на класс myClass объявлена, но не создана, или экземпляр объекта не назначен для ссылки на этот класс.
Чтобы это исправить, вы должны создать экземпляр (назначить объект для ссылки на этот класс).
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref = new myClass();
ref.prop1 = 1;
}
}
NullReferenceException или объектная ссылка, не установленная для экземпляра объекта, возникает, когда объект класса, который вы пытаетесь использовать, не создается. Например:
Предположим, что у вас есть класс с именем Student.
public class Student
{
private string FirstName;
private string LastName;
public string GetFullName()
{
return FirstName + LastName;
}
}
Теперь рассмотрим другой класс, в котором вы пытаетесь получить полное имя студента.
public class StudentInfo
{
public string GetStudentName()
{
Student s;
string fullname = s.GetFullName();
return fullname;
}
}
Как видно из вышеприведенного кода, оператор Student s - только объявляет переменную типа Student, обратите внимание, что в этом месте класс Student не создается. Следовательно, когда выполняется оператор s.GetFullName(), он генерирует исключение NullReferenceException.
Ну, простыми словами:
Вы пытаетесь получить доступ к объекту, который не создан или в данный момент отсутствует в памяти.
Итак, как справиться с этим:
Отладьте и дайте отладчику сломаться... Он напрямую приведет вас к сломанной переменной... Теперь ваша задача просто исправить это... Используя ключевое слово new в соответствующем месте.
Если это вызвано в некоторых командах базы данных, потому что объект не присутствует, тогда все, что вам нужно сделать, это сделать нулевую проверку и обработать ее:
if (i == null) { // Handle this }
Сложнее всего... если GC уже собрал объект... Обычно это происходит, если вы пытаетесь найти объект с помощью строк... То есть, находя его по имени объекта, может случиться так, что GC может уже Вычистил это... Это трудно найти и станет большой проблемой... Лучший способ справиться с этим - делать нулевые проверки везде, где это необходимо в процессе разработки. Это сэкономит вам много времени.
Под поиском по имени я подразумеваю, что некоторые фреймворки позволяют вам FIndObject, используя строки, и код может выглядеть так: FindObject ("ObjectName");
Буквально самый простой способ исправить NullReferenceExeption имеет два способа. Если у вас есть GameObject, например, с прикрепленным скриптом и переменной с именем rb (hardbody), эта переменная будет начинаться с нуля при запуске вашей игры.
Вот почему вы получаете NullReferenceExeption, потому что на компьютере нет данных, хранящихся в этой переменной.
Я буду использовать переменную RigidBody в качестве примера.
Мы можем действительно легко добавлять данные несколькими способами:
- Добавьте RigidBody к вашему объекту с помощью AddComponent > Физика> Rigidbody
Затем войдите в свой сценарий и введитеrb = GetComponent<Rigidbody>();
Эта строка кода лучше всего работает под вашимStart()
или жеAwake()
функции. - Вы можете добавить компонент программно и назначить переменную одновременно одной строкой кода:
rb = AddComponent<RigidBody>();
Дополнительные примечания: Если вы хотите, чтобы Unity добавила компонент к вашему объекту, и вы, возможно, забыли добавить его, вы можете ввести [RequireComponent(typeof(RigidBody))]
над объявлением вашего класса (пространство под всеми вашими использованиями).
Наслаждайтесь и получайте удовольствие от создания игр!
Типы ссылок по умолчанию равны нулю, чтобы указать, что они не ссылаются ни на один объект. Следовательно, если вы попытаетесь получить доступ к объекту, на который ссылается, а его нет, вы получите исключение NullReferenceException.
Например:
SqlConnection connection = null;
connection.Open();
Когда вы запустите этот код, вы получите:
System.NullReferenceException: Object reference not set to an instance of an object.
Вы можете избежать этой ошибки, кодируя это так:
if (connection != null){
connection.Open();
}
Примечание. Чтобы избежать этой ошибки, вы всегда должны инициализировать свои объекты, прежде чем пытаться что-либо с ними делать.
Если вы получаете это сообщение во время сохранения или компиляции сборки, просто закройте все файлы, а затем откройте любой файл для компиляции и сохранения.
Для меня причина была в том, что я переименовал файл, а старый файл все еще был открыт.
Чтобы использовать методы и член объекта, вы должны сначала создать этот объект. Если вы не создали его (переменная, которая должна содержать объект, не инициализирована), но вы пытаетесь использовать его методы или переменные, вы получите эту ошибку.
Иногда вы можете просто забыть выполнить инициализацию.
Отредактировано: new не может возвратить ноль, но исключение огня при неудаче. Давным-давно это было в некоторых языках, но не больше. Спасибо @Джон Сондерс за то, что указал на это.
Это в основном является нулевым ссылочным исключением. Как заявляет Microsoft,
Исключение NullReferenceException выдается при попытке доступа к члену типа, значение которого равно нулю.
Что это значит?
Это означает, что если какой-либо участник, который не имеет никакого значения, и мы заставляем этого участника выполнять определенную задачу, то система, несомненно, бросит сообщение и скажет:
"Эй, подождите, у этого члена нет значений, поэтому он не может выполнить задачу, которую вы передаете".
Само исключение говорит, что на что-то ссылаются, но чье значение не устанавливается. Таким образом, это означает, что это происходит только при использовании ссылочных типов, поскольку типы значений не могут быть обнуляемыми.
NullReferenceException не произойдет, если мы используем члены типа Value.
class Program
{
static void Main(string[] args)
{
string str = null;
Console.WriteLine(str.Length);
Console.ReadLine();
}
}
Приведенный выше код показывает простую строку, которой присваивается нулевое значение.
Теперь, когда я пытаюсь напечатать длину строки str, я получаю сообщение о необработанном исключении типа "System.NullReferenceException", потому что член str указывает на ноль и не может быть никакой длины ноль.
NullReferenceException также возникает, когда мы забываем создать экземпляр ссылочного типа.
Предположим, у меня есть метод класса и члена. Я не создал экземпляр своего класса, а только назвал свой класс. Теперь, если я попытаюсь использовать метод, компилятор выдаст ошибку или выдаст предупреждение (в зависимости от компилятора).
class Program
{
static void Main(string[] args)
{
MyClass1 obj;
obj.foo(); //Use of unassigned local variable 'obj'
}
}
public class MyClass1
{
internal void foo()
{
Console.WriteLine("hello from foo");
}
}
Компилятор для приведенного выше кода вызывает ошибку, что переменная obj не назначена, что означает, что наша переменная имеет нулевые значения или ничего. Компилятор для приведенного выше кода вызывает ошибку, что переменная obj не назначена, что означает, что наша переменная имеет нулевые значения или ничего.
Почему это происходит?
NullReferenceException возникает из-за нашей ошибки в том, что мы не проверили значение объекта. Мы часто оставляем значения объектов без контроля при разработке кода.
Это также возникает, когда мы забываем создавать экземпляры наших объектов. Использование методов, свойств, коллекций и т. Д., Которые могут возвращать или устанавливать нулевые значения, также может быть причиной этого исключения.
Как этого можно избежать?
Существуют различные способы и способы избежать этого известного исключения:
Явная проверка. Мы должны придерживаться традиции проверки объектов, свойств, методов, массивов и коллекций на предмет наличия нулевых значений. Это может быть просто реализовано с использованием условных операторов, таких как if-else, if-else и т. Д.
Обработка исключений: один из важных способов управления этим исключением. Используя простые блоки try-catch-finally, мы можем контролировать это исключение, а также вести его журнал. Это может быть очень полезно, когда ваше приложение находится на стадии разработки.
Нулевые операторы: Нулевой оператор объединения и нулевые условные операторы также могут быть полезны при установке значений для объектов, переменных, свойств и полей.
Отладчик: Для разработчиков у нас есть большое оружие отладки. Если мы столкнулись с NullReferenceException во время разработки, мы можем использовать отладчик, чтобы добраться до источника исключения.
Встроенный метод. Системные методы, такие как GetValueOrDefault(),IsNullOrWhiteSpace() и IsNullorEmpty(), проверяют наличие нулевых значений и присваивают значение по умолчанию, если существует нулевое значение.
Здесь уже есть много хороших ответов. Вы также можете проверить более подробное описание с примерами в моем блоге.
Надеюсь, это тоже поможет!
Это означает, что вы пытаетесь манипулировать чем-то, что имеет ссылку, но еще не инициализировано
Первое, что нужно сделать, это проверить каждый созданный экземпляр.
Используйте точки останова, часы, проверяйте значения переменных.
Следуйте трассировке стека и ищите точную строку и столбец, который создает проблему