У мене є якийсь код, і коли він виконується, він кидає NullReferenceException
, кажучи:
Посилання на об'єкт не встановлено для примірника об'єкта.
Що це означає, і що я можу зробити, щоб виправити цю помилку?
У мене є якийсь код, і коли він виконується, він кидає NullReferenceException
, кажучи:
Посилання на об'єкт не встановлено для примірника об'єкта.
Що це означає, і що я можу зробити, щоб виправити цю помилку?
Відповіді:
Ви намагаєтесь використовувати щось, що є null
(або Nothing
у VB.NET). Це означає, що ви або встановлюєте його null
, або ви ніколи не встановлюєте його ні на що.
Як і все інше, null
його пропускають навколо. Якщо це null
в методі "А", то може бути, що метод "В" перейшов null
до методу "А".
null
може мати різні значення:
NullReferenceException
.null
щоб вказати, що немає значущого значення. Зауважте, що C # має поняття змінних типів даних для змінних (наприклад, таблиці баз даних можуть мати нульові поля) - ви можете призначити null
їм, щоб вказати, що в ньому не зберігається значення, наприклад, int? a = null;
коли знак питання вказує, що дозволено зберігати null в змінна a
. Ви можете перевірити це або з, if (a.HasValue) {...}
або з if (a==null) {...}
. Зменшувані змінні, як a
цей приклад, дозволяють отримати доступ до значення за допомогою a.Value
явного або так само, як звичайного, через a
. a.Value
Видає InvalidOperationException
замість NullReferenceException
якщо a
ISnull
- ви повинні заздалегідь зробити перевірку, тобто якщо у вас є інша змінна-нульова змінна, int b;
то вам слід виконувати завдання типу if (a.HasValue) { b = a.Value; }
або коротше if (a != null) { b = a; }
.В решті цієї статті детальніше йдеться про помилки, які часто роблять багато програмістів, які можуть призвести до появи NullReferenceException
.
runtime
Метанні NullReferenceException
завжди означає те ж саме: ви намагаєтеся використовувати посилання, і посилання не ініціалізується (або він був коли - то инициализируется, але не більше не инициализирован).
Це означає, що посилання є null
, і ви не можете отримати доступ до членів (наприклад, методів) через null
посилання. Найпростіший випадок:
string foo = null;
foo.ToUpper();
Це призведе NullReferenceException
до другого рядка, оскільки ви не можете викликати метод екземпляра ToUpper()
на string
посилання, що вказує на null
.
Як знайти джерело NullReferenceException
? Окрім перегляду самого винятку, яке буде кинуто саме в тому місці, де воно відбувається, застосовуються загальні правила налагодження у Visual Studio: розміщуйте стратегічні точки перерви та перевіряйте ваші змінні , або наведення курсором миші на їх імена, відкриваючи ( Швидко) Переглядайте вікно або використовуючи різні налагоджувальні панелі, такі як Locals та Autos.
Якщо ви хочете дізнатися, де посилання знаходиться чи не встановлено, клацніть правою кнопкою миші його ім’я та виберіть "Знайти всі посилання". Потім ви можете розмістити точку перерви у кожному знайденому місці та запустити свою програму із доданим налагоджувачем. Кожен раз, коли налагоджувач перерветься на таку точку розриву, вам потрібно визначити, чи очікуєте ви, що посилання буде недійсним, перевірити змінну та переконатися, що вона вказує на екземпляр, коли ви очікуєте її.
Слідуючи потік програми таким чином, ви можете знайти місце, де екземпляр не повинен бути нульовим, і чому він неправильно встановлений.
Деякі загальні сценарії, коли виняток можна кинути:
ref1.ref2.ref3.member
Якщо ref1 або ref2 або ref3 недійсні, ви отримаєте a 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; }
}
Вкладені колекції Initializers
ведуть себе однаково:
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
. Initializer
Синтаксис колекції не створює колекцію для 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
}
}
###Bad Naming Conventions:
If you named fields differently from locals, you might have realized that you never initialized the field.
публічний клас Form1 {приватний клієнт-замовник;
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;
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!";
}
}
// if the "FirstName" session value has not yet been set,
// then this line will throw a NullReferenceException
string firstName = Session["FirstName"].ToString();
Якщо виняток виникає при посиланні на властивість @Model
у ASP.NET MVC View
, вам потрібно зрозуміти, що 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
елементи керування створюються під час виклику InitializeComponent
в порядку, у якому вони відображаються у візуальному дереві. A 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
а, але повертає a, null
коли кастинг виходить з ладу (і коли someObject
він сам є нульовим). Тож пам’ятайте про це.
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()
для nullable
типів значень, щоб вказати значення за замовчуванням, коли вони є 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();
Тепер змінна назва буде нульовою замість того, щоб викидати виняток. C # 6 вводить для цього коротший синтаксис:
var title = person.Title?.ToUpper();
Це призведе до появи змінної заголовка null
, а виклик до ToUpper
не робиться, якщо person.Title
є null
.
Звичайно, вам все одно доведеться перевірити title
наявність null або використовувати оператор умови null разом з оператором coleescing 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<sup>th</sup>
елемент.
Введені C# 8
там нульові типи контексту та нульові еталонні типи виконують статичний аналіз на змінні та надають попередження компілятора, якщо значення потенційно може бути нульовим або встановлено на нуль. Нульові типи посилань дозволяють явним чином дозволити типам бути недійсними.
Контекст анотації, що міняється, і контекст попереджувального попередження можуть бути встановлені для проекту, використовуючи Nullable
елемент у вашому csproj
файлі. Цей елемент налаштовує, як компілятор інтерпретує нульовість типів та які попередження створюються. Дійсні налаштування:
Нульовий тип посилання відмічається, використовуючи той самий синтаксис, що і типи нульових значень: a ?
додається до типу змінної.
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
на «Об’єкти», ви побачите, що ця методика використовується впродовж усього. Це трохи більш незграбно писати, але це значно спрощує налагодження помилок недійсності. Оптимізуйте свій код для зручності абонента, а не зручності автора .
C#
має "небезпечний" режим, який, як випливає з назви, надзвичайно небезпечний, оскільки нормальні механізми безпеки, що забезпечують безпеку пам’яті та безпеку типу, не застосовуються. Ви не повинні писати небезпечний код, якщо не маєте глибокого та глибокого розуміння того, як працює пам'ять .
У небезпечному режимі вам слід знати два важливі факти:
Щоб зрозуміти, чому це, це допомагає зрозуміти, як .NET в першу чергу створює нульові винятки з відновлення. (Ці деталі стосуються .NET, що працює в Windows; інші операційні системи використовують аналогічні механізми.)
Пам'ять віртуалізується в Windows
; кожен процес отримує віртуальний простір пам'яті з багатьох "сторінок" пам'яті, які відслідковуються операційною системою. На кожній сторінці пам’яті встановлені прапори, які визначають, яким чином вона може бути використана: читати, писати, виконувати тощо. Низька сторінка позначається як «видають помилку , якщо коли - небудь використовували в будь-якому випадку».
І нульовий вказівник, і нульова посилання C#
внутрішньо представлені як нульове число, і тому будь-яка спроба знеструмлення його у відповідному сховищі пам’яті призводить до помилки операційної системи. Потім .NET виконує виявлення цієї помилки та перетворює її на виняток з нульовим відхиленням.
Ось чому перенаправлення як нульового покажчика, так і нульової посилання створює той самий виняток.
А як щодо другого пункту? Перенаправлення будь-якого недійсного вказівника, який потрапляє на найнижчу сторінку віртуальної пам'яті, викликає ту саму помилку операційної системи і, отже, той самий виняток.
Чому це має сенс? Ну, припустимо, у нас є структура, що містить два входи та некерований покажчик, рівний нулю. Якщо ми спробуємо знеструмити другий int в структурі, CLR
то не буде спроба отримати доступ до сховища в нульовому місці; він отримає доступ до сховища за адресою чотири. Але логічно це нульове відхилення, оскільки ми дістаємося до цієї адреси через null.
Якщо ви працюєте з небезпечним кодом і отримуєте нульовий виняток відношення, просто пам’ятайте, що покажчик, що порушує порушення, не повинен бути нульовим. Це може бути будь-яке місце на нижній сторінці, і цей виняток буде створено.
NullReference Exception
Для Visual Basic нічим не відрізняється від такого в C # . Зрештою, вони обидва звітують про той самий виняток, визначений у .NET Framework, який вони обидва використовують. Причини, унікальні для Visual Basic, рідкісні (можливо, лише одна).
У цій відповіді будуть використані терміни, синтаксис та контекст Visual Basic. Використовувані приклади походять із великої кількості попередніх запитань щодо переповнення стека. Це для досягнення максимальної актуальності, використовуючи типи ситуацій, які часто спостерігаються у публікаціях. Трохи більше пояснень надається і тим, хто може це потребувати. Приклад, подібний до вашого, дуже ймовірно, перерахований тут.
Примітка:
NullReferenceException
(NRE), як його знайти, як виправити та як уникнути. NRE може бути викликаний багатьма способами, тому це навряд чи буде вашою єдиною зустріччю.Повідомлення "Об'єкт не встановлено на екземпляр" Об'єкта " означає, що ви намагаєтесь використовувати об'єкт, який не був ініціалізований. Це зводиться до одного з таких:
Оскільки проблема - це посилання на об'єкт Nothing
, відповідь полягає в тому, щоб вивчити їх, щоб з'ясувати, яка саме. Потім визначте, чому вона не ініціалізована. Тримайте курсор миші на різних змінних, і Visual Studio (VS) покаже їх значення - винуватець буде Nothing
.
Ви також повинні видалити будь-які блоки Try / Catch із відповідного коду, особливо ті, де у блоці Catch нічого немає. Це призведе до збою вашого коду, коли він намагається використовувати об'єкт, який є Nothing
. Це те, що ви хочете, тому що воно визначить точне місце виникнення проблеми та дозволить визначити об'єкт, що його викликає.
А MsgBox
в лові, який відображатиметься, Error while...
буде мало допомогти. Цей метод також призводить до дуже поганих запитань щодо переповнення стека, оскільки ви не можете описати фактичний виняток, залучений об'єкт або навіть рядок коду, де це відбувається.
Ви також можете скористатися Locals Window
( Налагодження -> Windows -> Місцеві організації ) для вивчення своїх об'єктів.
Після того, як ви дізнаєтеся, що і де проблема, це виправити, як правило, досить легко і швидше, ніж ставити нове запитання.
Дивись також:
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
оператора є причиною №1, яку миNullReference Exceptions
бачимо у розглянутих питаннях переповнення стека.Visual Basic намагається зробити процес очищенням неодноразово, використовуючи
New
: ВикористанняNew
Оператора створює новий об’єкт і викликаєSub New
- конструктор - там, де ваш об’єкт може виконати будь-яку іншу ініціалізацію.
Щоб було зрозуміло, Dim
(або Private
) оголошує лише змінну та її Type
. Обсяг змінної - чи існує вона для всього модуля / класу або є локальним для процедури - визначається , де вона оголошена. Private | Friend | Public
визначає рівень доступу, а не Обсяг .
Для отримання додаткової інформації див:
Масиви також повинні бути примірниками:
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
об’єкт Dataset був оголошений, але екземпляр так і не був створений. 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 .
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
елемент може не існувати.
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...
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
Це досить поширений спосіб отримати НРЕ. У C #, залежно від того, як це закодовано, IDE повідомляє, що Controls
не існує в поточному контексті, або "не може посилатися на нестатичний член". Отже, певною мірою це лише ситуація з ВБ. Він також складний, оскільки може призвести до каскаду відмов.
Масиви та колекції не можна ініціалізувати таким чином. Цей код ініціалізації запуститься до того, як конструктор створить Form
або Controls
. В результаті:
somevar
Призначення призведе до негайного Ярду , тому що нічого не має .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 на цій панелі або GroupBox. Також контроль не буде повернутий, коли ім'я керування неправильно написано ( "TeStBox2"
). У таких випадках Nothing
знову зберігатимуться в цих елементах масиву, і при спробі посилання на нього з'явиться NRE.
Тепер їх слід легко знайти, коли ви знаєте, що шукаєте:
"Button2" знаходиться на a 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 може приховати проблему та призвести до нових:
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
блок - дитячий майданчик. Цей ОП був здивований, чому він отримує НРЕ в Finally
блоці. В інших ситуаціях порожній Catch
може призвести до чогось ще набагато далі за течією, що перебуває вниз за течією, і призведе до того, що ви витратите час на пошук неправильних речей у неправильному місці для проблеми. (Вищеописаний "мовчазний виняток" надає однакове розважальне значення.)
Засіб усунення
Не використовуйте порожні блоки "Try / Catch" - нехай код виходить з ладу, щоб ви могли а) визначити причину b) визначити місце розташування та в) застосувати належний засіб захисту. Блоки "Try / Catch" не приховують винятків від людини, яка має унікальну кваліфікацію для їх виправлення - розробника.
For Each row As DataGridViewRow In dgvPlanning.Rows
If Not IsDBNull(row.Cells(0).Value) Then
...
IsDBNull
Функція використовується для перевірки , якщо значення одно System.DBNull
: З MSDN:
Значення System.DBNull вказує на те, що Об'єкт представляє відсутні або неіснуючі дані. DBNull не є тим самим, що нічого, що вказує на те, що змінна ще не була ініціалізована.
Засіб усунення
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
Якщо a CheckBox
з chkName
не можна знайти (або існує в a GroupBox
), то chk
буде "Nothing" і спроба посилання на будь-яке властивість призведе до виключення.
Засіб усунення
If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...
Періодично у 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
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
може спричинити 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 з керуванням календаря:
<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />
Тут SelectedDate
насправді є властивість - DateTime
типу - типу Calendar
Web Control, і прив'язка може ідеально повернути щось недійсне. Неявний генератор ASP.NET створить фрагмент коду, який буде еквівалентний наведеному вище коду. І це призведе до того, NullReferenceException
що досить важко помітити, оскільки він лежить у створеному ASP.NET коді, який добре поєднує ...
DateTime x = (DateTime) o as DateTime? ?? defaultValue;
Це означає, що змінна, про яку йдеться, не вказується ні на що. Я міг би генерувати це так:
SqlConnection connection = null;
connection.Open();
Це призведе до помилки, оскільки, хоча я оголосив змінну " connection
", вона нічого не вказує. Коли я намагаюся зателефонувати учаснику " Open
", його немає для вирішення, і це призведе до помилки.
Щоб уникнути цієї помилки:
object == null
.Інструмент Resharper JetBrains визначить кожне місце у вашому коді, яке має можливість помилки з нульовим посиланням, що дозволяє ввести нульову перевірку. Ця помилка є джерелом помилок номер один, IMHO.
Це означає, що ваш код використовував змінну посилання на об'єкт, на яку було встановлено нуль (тобто він не посилався на фактичний примірник об'єкта).
Щоб запобігти помилці, об’єкти, які можуть бути нульовими, повинні бути перевірені на нуль перед їх використанням.
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
}
Майте на увазі, що незалежно від сценарію причина завжди однакова в .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 .
Оновлення C # 8.0, 2019: Мінусні типи посилань
C # 8.0 вводить нульові еталонні типи та нерегульовані типи посилань . Тож слід перевіряти лише нульові типи посилань, щоб уникнути NullReferenceException .
Якщо ви не ініціалізували тип посилання і хочете встановити чи прочитати одну з його властивостей, він видасть 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, важливо знати різницю між типами значень та [ типовими типами] [3].
Отже, якщо ви маєте справу з типами значень , NullReferenceExceptions не може виникнути. Хоча вам потрібно бути настороженими при роботі з еталонними типами !
Тільки типи посилань, як випливає з назви, можуть містити посилання або вказувати буквально на ніщо (або "null"). Тоді як типи значень завжди містять значення.
Довідкові типи (їх потрібно перевірити):
Типи значень (їх можна просто проігнорувати):
Інший випадок, коли це 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
є несумісні типи; a Car
неможливо перетворити / передати в а Book
. Коли цей випадок не вдається, as
повертається null
. Використання mybook
після цього викликає a 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 ()
Хоча те, що викликає NullReferenceExceptions та підходи до уникнення / виправлення такого винятку, розглянуто в інших відповідях, те, що багато програмістів ще не дізналися, - як самостійно налагоджувати такі винятки під час розробки.
У Visual Studio це зазвичай легко завдяки відладчику Visual Studio .
По-перше, переконайтеся, що правильна помилка буде зафіксована - див. Як дозволити перелом на 'System.NullReferenceException' у VS2010? Примітка 1
Потім або Почніть з налагодження (F5), або додайте [налагоджувач VS] до запущеного процесу . При нагоді це може бути корисно використовувати Debugger.Break
, що підкаже запуск налагоджувача.
Тепер, коли NullReferenceException буде кинуто (або не оброблено), налагоджувач зупиниться (пам'ятаєте правило, встановлене вище?) На рядку, в якому сталося виключення. Іноді помилку буде легко помітити.
Наприклад, у наступному рядку єдиний код, який може спричинити виняток, - якщо його myString
оцінюють на нуль. Це можна перевірити, подивившись у вікно годинника або виконуючи вирази у негайному вікні .
var x = myString.Trim();
У більш розвинених випадках, таких як наступний, вам потрібно скористатися однією з прийомів, описаних вище (Watch або Immediate Windows), щоб перевірити вирази, щоб визначити, чи str1
було null або str2
null.
var x = str1.Trim() + str2.Trim();
Після того, коли виняток становить кидок був розташований, зазвичай тривіальної причини задом наперед , щоб з'ясувати , де нульове значення було [неправильно] ввів -
Знайдіть час, необхідний для розуміння причини винятку. Перевірте наявність нульових виразів. Перевірте попередні вирази, які могли призвести до таких нульових виразів. Додайте точки перерви та пройдіть через програму, якщо потрібно. Використовуйте налагоджувач.
1 Якщо Break on Throw занадто агресивний і відладчик зупиняється на NPE в .NET або сторонній бібліотеці, Break on User-Unhandled може бути використаний для обмеження вилучених винятків. Крім того, VS2012 представляє Just My Code, який я рекомендую також включити.
Якщо ви налагоджуєте функцію Just My Code увімкнено, поведінка дещо відрізняється. Якщо увімкнено функцію Just My Code, налагоджувач ігнорує винятки загальної мови (CLR) першої можливості, які викидаються за межі Мого коду та не проходять через Мій код
Саймон Мур’є подав такий приклад :
object o = null;
DateTime d = (DateTime)o; // NullReferenceException
де конверсія (викид) з розблокування ( з одного класу або , або з типу інтерфейсу) у тип значення (відмінний від ) сам по собі дає значення . object
System.ValueType
System.Enum
Nullable<>
NullReferenceException
В іншому напрямку, A бокс перетворення з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, кодом якої є клас Контакт, і ви маєте ім'я особи Contact.
Потім наступний код видасть NullReferenceException при виклику контексту.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;}
}
Помилка виникає, коли і сутність, і клас, що знаходиться за кодом, знаходяться в одному просторі імен. Щоб виправити це, перейменуйте клас сутності або клас код, що знаходиться за кодом Contact.aspx.
Причина Я досі не впевнений у своїй причині. Але кожного разу, коли будь-який із класів сутності поширить System.Web.UI.Page, ця помилка виникає.
Для обговорення подивіться на NullReferenceException в DbContext.saveChanges ()
Інший загальний випадок, коли можна отримати цей виняток, стосується знущальних класів під час тестування одиниць. Незалежно від використовуваної рамки глузування, ви повинні переконатися, що всі відповідні рівні ієрархії класів належним чином висміюються. Зокрема, з усіх властивостей, на HttpContext
які посилається тестовий код, слід висміяти.
Див. " NullReferenceException, кинутий під час тестування користувальницького AuthorizationAttribute ", для дещо детального прикладу.
У мене є інша перспектива відповісти на це. Цей тип відповідей "що ще я можу зробити, щоб цього уникнути? "
Під час роботи на різних рівнях , наприклад у програмі MVC, контролеру потрібні послуги для виклику бізнес-операцій. У таких сценаріях контейнер ін'єкції залежності може використовуватися для ініціалізації служб, щоб уникнути 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.
Як варіант, дизайн за контрактом можна застосувати, використовуючи твердження .
ОНОВЛЕННЯ: Варто згадати, що цей термін був введений Бертран Меєром у зв'язку з його розробкою мови програмування Ейфеля .
A 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
String.Empty.ToLower()
не викине нульовий посилання на виняток. Він являє собою фактичний рядок, хоч і порожній (тобто ""
). Оскільки в цьому об’єкті слід закликати ToLower()
, не було б сенсу викидати туди нульовий виняток.
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
Налагодження показало, що модель була 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 неправильно читав амперсанди та дужки.
Html.Partial
, ні@Html.Partial
Null
), тому я знав, що помилка була в тому, як я надсилаю Модель.
Що ви можете з цим зробити?
Тут є багато хороших відповідей, що пояснюють, що таке нульова посилання та як її налагодити. Але про те, як запобігти проблемі або принаймні полегшити вилов, є дуже мало.
Перевірте аргументи
Наприклад, методи можуть перевірити різні аргументи, щоб побачити, чи є вони нульовими, і кинути an ArgumentNullException
, виняток, очевидно, створений саме для цієї мети.
Конструктор для ArgumentNullException
рівних приймає назву параметра та повідомлення як аргументи, щоб ви могли точно сказати розробнику, у чому проблема.
public void DoSomething(MyObject obj) {
if(obj == null)
{
throw new ArgumentNullException("obj", "Need a reference to obj.");
}
}
Використовуйте Інструменти
Також є кілька бібліотек, які можуть допомогти. Наприклад, "Resharper" може надати вам попередження під час написання коду, особливо якщо ви використовуєте їх атрибут: NotNullAttribute
Існує "Код контрактів Microsoft", де ви використовуєте синтаксис, 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);
}
Як ви бачите вище, як з нульовим, ви отримаєте доступ до базового значення через 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)
.
Цікаво, що жодна з відповідей на цій сторінці не згадує два крайні випадки, сподіваюся, ніхто не подумає, якщо я додам їх:
Загальні словники в .NET не є безпечними для потоків, і іноді вони можуть викинути NullReference
або навіть (частіше) a, KeyNotFoundException
коли ви намагаєтесь отримати доступ до ключа з двох одночасних потоків. Виняток є досить оманливим у цьому випадку.
Якщо a NullReferenceException
закидається unsafe
кодом, ви можете подивитися на змінні вказівника та перевірити їх на наявність IntPtr.Zero
чи щось. Це те саме ("виняток з нульового вказівника"), але в небезпечному коді змінні часто переносяться на типи значень / масиви тощо, і ти б'єш головою об стіну, цікавлячись, як тип типу може кинути це виняток.
(Ще одна причина невикористання небезпечного коду, якщо він вам, до речі, не потрібен)
null
того, чим?
Ви можете виправити NullReferenceException чистим способом, використовуючи Null-conditional Operators в c # 6 і написати менше коду для обробки нульових перевірок.
Він використовується для тестування на null перед виконанням операції доступу члена (?.) Або індексу (? [).
Приклад
var name = p?.Spouse?.FirstName;
еквівалентно:
if (p != null)
{
if (p.Spouse != null)
{
name = p.Spouse.FirstName;
}
}
Результатом є те, що ім'я буде нульовим, коли p є нульовим або коли p.Spouse є null.
В іншому випадку імені змінної буде призначено значення p.Spouse.FirstName.
Докладніше: Нульові умовні оператори
Рядок помилки "Посилання на об'єкт не встановлено для екземпляра об'єкта". Вказується, що ви не присвоїли об'єкту екземпляра посилання на об'єкт, і ви все ще отримуєте доступ до операцій / методів цього об'єкта.
наприклад: скажімо, у вас є клас під назвою 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 або посилання на Object, не встановлений для екземпляра об'єкта, виникає, коли об'єкт класу, який ви намагаєтеся використовувати, не є екземпляром. Наприклад:
Припустимо, що у вас є клас на ім'я Студент.
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.
Ну, простіше кажучи:
Ви намагаєтеся отримати доступ до об'єкта, який не створений або наразі не є в пам'яті.
Отже, як вирішити це:
Налагоджуйте і нехай лампочка зламається ... Це безпосередньо переведе вас до змінної, яка зламана ... Тепер ваше завдання - це просто виправити це .. Використання нового ключового слова у відповідному місці.
Якщо він викликаний деякими командами бази даних, оскільки об'єкт відсутній, то все, що вам потрібно зробити, - це зробити нульову перевірку та обробити її:
if (i == null) {
// Handle this
}
Найскладніше .. якщо GC вже зібрав об’єкт ... Це, як правило, відбувається, якщо ви намагаєтесь знайти об’єкт за допомогою рядків ... Тобто, знаходження його за назвою об'єкта, то може статися, що GC може вже Почистили його ... Це важко знайти і стане досить проблемою ... Кращий спосіб вирішити це - зробити нульові перевірки там, де це необхідно в процесі розробки. Це заощадить вам багато часу.
Знаходячись по імені, я маю на увазі, що деякі рамки дозволяють вам FIndObjects за допомогою рядків і код може виглядати так: FindObject ("ObjectName");
Буквально найпростіший спосіб виправити NullReferenceExeption має два способи. Якщо у вас є GameObject, наприклад, із доданим сценарієм та змінною з назвою rb (rigidbody), ця змінна запуститься нульовою при запуску гри.
Ось чому ви отримуєте NullReferenceExeption, оскільки на комп'ютері немає даних, що зберігаються в цій змінній.
Я буду використовувати приклад змінної RigidBody.
Ми можемо додавати дані дуже легко насправді кількома способами:
rb = GetComponent<Rigidbody>();
Start()
або Awake()
функцій. rb = AddComponent<RigidBody>();
Подальші примітки: Якщо ви хочете, щоб єдність додавала компонент до вашого об'єкта, і ви, можливо, забули додати його, ви можете набрати [RequireComponent(typeof(RigidBody))]
вище декларації свого класу (пробіл під усіма вашими умовами).
Насолоджуйтесь і отримуйте задоволення, роблячи ігри!
Якщо ми розглядаємо загальні сценарії, коли цей виняток можна кинути, отримуючи доступ до властивостей, розташованих у верхній частині об'єкта.
Наприклад:
string postalcode=Customer.Address.PostalCode;
//if customer or address is null , this will through exeption
тут, якщо адреса нульова, ви отримаєте NullReferenceException.
Отже, як практика, ми завжди повинні використовувати нульову перевірку, перш ніж отримувати доступ до властивостей таких об'єктів (особливо в загальних)
string postalcode=Customer?.Address?.PostalCode;
//if customer or address is null , this will return null, without through a exception
Це в основному є виключенням з нульовою посиланням . Як заявляє Microsoft,
Виняток NullReferenceException видається при спробі доступу до члена типу, значення якого є null.
Це означає, що якщо будь-який член, який не має жодного значення, і ми змушуємо його виконати певне завдання, система, безперечно, кине повідомлення та скаже-
"Привіт, чекай, цей член не має значень, тому він не може виконувати завдання, яке ти йому передаєш".
Саме виняток говорить про те, що щось передається, але значення якого не встановлюється. Отже, це означає, що це відбувається лише під час використання еталонних типів, оскільки типи значень не підлягають нулюванню.
NullReferenceException не відбудеться, якщо ми використовуємо члени типу Значення.
class Program
{
static void Main(string[] args)
{
string str = null;
Console.WriteLine(str.Length);
Console.ReadLine();
}
}
Наведений вище код показує просту рядок, який присвоюється символу a нульове значення.
Тепер, коли я намагаюся надрукувати довжину рядка str , я отримую необроблений виняток типу 'System.NullReferenceException' оскільки str str вказує на null, а довжина null не може бути.
' 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-нарешті", ми можемо контролювати цей виняток, а також вести журнал його. Це може бути дуже корисно, коли ваша заявка знаходиться на етапі виробництва.
Нульові оператори: Оператор Null Coalescing та null умовні оператори також можуть бути корисними під час встановлення значень для об'єктів, змінних, властивостей та полів.
Налагоджувач: Для розробників у нас є велика зброя налагодження. Якщо ми стикаємося з NullReferenceException під час розробки, ми можемо скористатися налагоджувачем, щоб дістатися до джерела винятку.
Вбудований метод: системні методи, такі як GetValueOrDefault (), IsNullOrWhiteSpace () та IsNullorEmpty (), перевіряють наявність нулів і присвоюють значення за замовчуванням, якщо є нульове значення.
Тут вже багато хороших відповідей. Ви також можете перевірити більш детальний опис із прикладами в моєму блозі .
Сподіваюся, що це теж допомагає!
Якщо хтось отримує це повідомлення під час збереження або збирання збірки, просто закрийте всі файли, а потім відкрийте будь-який файл для компіляції та збереження.
Для мене причиною було те, що я перейменував файл і старий файл все ще був відкритий.