Питання Що таке NullReferenceException, і як я можу це виправити?


У мене є код, і коли він виконує, він кидає а NullReferenceException, кажучи:

Довідник об'єкта не встановлено для екземпляра об'єкта.

Що це означає, і що я можу зробити, щоб виправити цю помилку?


1878


походження


Винятковий помічник у VS 2017 буде більш корисним для діагностики причини цього винятку - blogs.msdn.microsoft.com/visualstudio/2016/11/28/... під Новий допоміжний виняток. - Zev Spitz
Не можу ми просто сказати "об'єкт не був ініціалізований"? Отже, якщо у вас є декларація змінної: SomeClass myVariable; це створить myVariable з посиланням на SomeClass, але воно не ініціалізується і буде рівним нулю. Ви повинні викликати ініціалізацію класу, виконавши деякий клас MyVariable = new SomeClass (); Або, якщо ви повертаєте посилання на іншу змінну: SomeClass myVariable = anotherVariableDeclared (); - Arvin Amir
@Arvin як щодо `MfClass - John Saunders
Шановні майбутні відвідувачі, відповіді на це питання однаково стосуються і до ArgumentNullException. Якщо ваше запитання було закрито як дублікат цього, і у вас є ANE, дотримуйтесь інструкцій у відповідях на налагодження та виправте вашу проблему. - Will
@will ANE має відбутися лише у тому випадку, якщо як параметр передано нульовий. Чи можете ви навести приклад, якщо питання ANE закрито як дублікат цього? - John Saunders


Відповіді:


Що таке причина?

Нижня лінія

Ви намагаєтесь використати щось таке null (або Nothing у VB.NET). Це означає, що ви або встановили це null, або ніколи взагалі нічого не встановлюєте.

Як і все інше null проходить навколо. Якщо це null  в Метод "А" може бути таким, що метод "В" пройшов а null  до метод "А".

null може мати різні значення:

  1. Змінні об'єкта, які є неініціалізований і отже не вказати нічого. У цьому випадку, якщо ви отримуєте доступ до властивостей або методів таких об'єктів, це викликає a NullReferenceException.
  2. Розробник є використовуючи 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, і ви не можете отримати доступ до учасників (наприклад, методів) через a null довідка Найпростіший випадок:

string foo = null;
foo.ToUpper();

Це кине а NullReferenceException на другій лінії, оскільки ви не можете викликати метод екземпляра ToUpper() на string посилання, що вказує на null.

Налагодження

Як ви знайдете джерело a NullReferenceException? Окрім розгляду самого винятку, яке буде викинути саме там, де це відбувається, застосовуються загальні правила налагодження у Visual Studio: розміщення стратегічних точок переходу та перевірте ваші змінні, наведенням миші на імена, відкриття вікна (Quick) Watch або використання різних панелей налагодження, таких як Locals і Autos.

Якщо ви хочете з'ясувати, де посилання встановлено або не встановлено, клацніть правою кнопкою миші його ім'я та виберіть "Знайти всі посилання". Потім ви можете встановити точку зупинки на кожному знайденому місці та запустити програму за допомогою доданого налагодження. Кожного разу, коли відладчик розбивається на таку точку зупинки, вам слід визначити, чи очікуєте, що посилання буде не нульовим, перевірити змінну та перевірити, чи вказує на екземпляр, коли ви очікуєте це.

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

Приклади

Деякі загальні сценарії, за якими можна викинути виняток:

Загальний

ref1.ref2.ref3.member

Якщо ref1 або ref2 або ref3 є null, то ви отримаєте a NullReferenceException. Якщо ви хочете вирішити проблему, то з'ясуйте, який з них є нульовим, переписавши вираз на його простіший еквівалент:

var r1 = ref1;
var r2 = r1.ref2;
var r3 = r2.ref3;
r3.member

Зокрема, в Росії HttpContext.Current.User.Identity.Name, the HttpContext.Current може бути нульовим, або User власність може бути нульовою, або Identity майно може бути нульовим.

Непрямий

public class Person {
    public int Age { get; set; }
}
public class Book {
    public Person Author { get; set; }
}
public class Example {
    public void Foo() {
        Book b1 = new Book();
        int authorAge = b1.Author.Age; // You never initialized the Author property.
                                       // there is no Person to get an Age from.
    }
}

Якщо ви хочете уникнути нульової довідки дитини (особи), ви можете ініціалізувати його у конструкторі об'єкта батьків (Book).

Ініціалізатори вкладеного об'єкта

Те саме стосується ініціаторів вкладеного об'єкта:

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" });

The 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, але повертає a null коли відлиття збій (і коли якийсь об'єкт сам по собі нульовий). Отож, пам'ятайте про це.

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].

Стовпчаста для надання значення за замовчуванням, коли a 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;
}

Використовуйте оператор null condition: ?. або ?[x] для масивів (доступні в C # 6 і VB.NET 14):

Це також іноді називають безпечною навігацією або оператором Elvis (за формою). Якщо вираз на лівій стороні оператора є нульовим, то права частина не буде оцінена, а замість нього буде повернуто нуль. Це означає такі випадки:

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 для нуля або використовувати оператор нульового стану разом з оператором нульового коалесування (??), щоб надати значення за замовчуванням:

// 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 є нульовим, вираз повертає нуль, і ви можете безпечно перевірити його. Якщо він містить масив, він буде виконуватись так само, як: elem = myIntArray[i]; і повертає яго елемент

Спеціальні методи для налагодження та фіксації null derefs в ітераторі

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 # має "небезпечний" режим, який, як випливає з назви, є надзвичайно небезпечним, оскільки звичайні механізми безпеки, які забезпечують безпеку пам'яті та безпеку типу, не застосовуються. Не слід писати небезпечний код, якщо у вас немає глибокого та глибокого розуміння роботи пам'яті.

У небезпечному режимі ви повинні бути в курсі двох важливих фактів:

  • зняття нуля покажчик виробляє таке ж виняток, як dereferencing null довідка
  • вилучення недійсного не нульового вказівника може виробляти це виняток в деяких випадках

Щоб зрозуміти, чому це є, це допомагає зрозуміти, як .NET в першу чергу виробляє винятки з нульовими винятками. (Ці відомості стосуються. NET, що працює під керуванням Windows, інші операційні системи використовують подібні механізми.)

Пам'ять віртуалізується в Windows; кожен процес отримує віртуальну пам'ять багатьох "сторінок" пам'яті, відстежуваних операційною системою. На кожній сторінці пам'яті встановлено прапори, які визначають спосіб використання: читання, написання, виконання та ін. The найнижчий сторінка позначена як "породити помилку, якщо вона коли-небудь використовувалася будь-яким способом".

Як нульовий покажчик, так і нульова посилання в C # внутрішньо представлені як число нуль, і тому будь-яка спроба вилучити її у відповідну пам'ять з пам'яті викликає помилку в операційній системі. Тоді час виконання .NET виявляє цю помилку і перетворює її в виняток нульового значення.

Ось чому вилучення як нульового покажчика, так і нульової посилання виводить таке саме виключення.

А як щодо другого пункту? Знищення каналів будь-який недійсний покажчик, що потрапляє на найнижчу сторінку віртуальної пам'яті, спричиняє ту ж саму помилку операційної системи і, таким чином, той же виняток.

Чому це має сенс? Ну, припустимо, у нас є структура, що містить два інтродукції, а некерований покажчик дорівнює нулю. Якщо ми спробуємо вимкнути другий int в структурі, CLR не буде намагатися отримати доступ до сховища на нульовому місці; він буде мати доступ до сховища на місці чотири. Але це логічно, це нульова відмітка, оскільки ми звертаємося до такої адреси через нуль

Якщо ви працюєте з небезпечним кодом, і ви отримуєте виняток з нульовим значенням dereference, слід пам'ятати, що покажчик, що порушує, не повинен бути нульовим. Це може бути будь-яке місце на найнижчій сторінці, і це виняток буде зроблено.


2111



Можливо, це дурний коментар, але не буде першим і найкращим способом уникнути цієї проблеми, щоб ініціалізувати об'єкт? Для мене, якщо така помилка виникає, це звичайно тому, що я забув ініціалізувати щось на кшталт елемента масиву. Я думаю, що набагато рідше визначити об'єкт як нуль, а потім посилатися на нього. Може бути, дасть шлях вирішити кожну проблему, що примикає до опису. Ще хороший пост. - JPK
Що робити, якщо немає об'єкта, а скоріше повернене значення з методу або властивості? - John Saunders
Приклад книги / автора трохи дивно .... Як це навіть складається? Як інтелектуальна робота навіть працює? Що це, я не добре з комп'ютером ... - Will
@Will: чи допомагає мій останній редагування? Якщо ні, то будь ласка, будь ласка, більш ясним, що ви бачите як проблему. - John Saunders
@JohnSaunders О, ні, вибач, я мав на увазі версію ініціалізатора об'єкта. new Book { Author = { Age = 45 } }; Як внутрішня ініціалізація навіть ... Я не можу придумати ситуацію, коли внутрішня ініціатива коли-небудь буде працювати, однак вона компілює і розважає ... Якщо тільки для структур? - Will


Виняток NullReference - Visual Basic

The NullReference Exception за Visual Basic нічим не відрізняється від C #. Зрештою, вони обидва повідомляють однакове виключення, визначене в .NET Framework, яке вони обидва використовують. Причини, унікальні для Visual Basic, рідкісні (можливо, лише один).

Ця відповідь буде використовувати терміни, синтаксис та контекст Visual Basic. Приклади використовуються з великої кількості минулих питань переповнення стаканів. Це, щоб максимізувати релевантність, використовуючи видів ситуацій, часто зустрічаються в повідомленнях. Трохи більше пояснень також надається тим, кому це може знадобитися. Приклад подібний до вашої дуже ймовірно, перераховані тут.

Примітка:

  1. Це концепція: не існує коду для вставки в ваш проект. Він покликаний допомогти вам зрозуміти, що викликає а NullReferenceException (NRE), як це знайти, як це виправити, і як уникнути цього. NRE може бути викликано багатьма способами, тому це навряд чи буде вашою єдиною зустріччю.
  2. Приклади (з повідомлень зі стовпчика переповнення) не завжди показують найкращий спосіб зробити щось в першу чергу.
  3. Як правило, найпростіший засіб використовується.

Основний зміст

Повідомлення "Об'єкт не налаштований на екземпляр об'єкта" означає, що ви намагаєтеся використовувати об'єкт, який не був ініціалізований. Це зводиться до одного з них:

  • Ваш код оголосив об'єктна змінна, але це не так ініціалізувати це (створити екземпляр або "екземплярце)
  • Те, що ваш код припустив, ініціалізував об'єкт, не було
  • Можливо, інший код достроково призупинив використання об'єкта

Визначення причини

Оскільки проблема - це посилання на об'єкт Nothing, відповідь - вивчити їх, щоб з'ясувати, яка з них. Потім визначте, чому він не ініціалізується. Тримайте курсор миші над різними змінними, і Visual Studio (VS) покаже їх значення - винуватця буде Nothing.

IDE debug display

Ви також повинні вилучити будь-які блоки "спроба / схоплення" з відповідного коду, особливо тих, де немає нічого в блоці "Зловмисник". Це призведе до збою вашого коду, коли він намагатиметься використовувати об'єкт, який є Nothing. Це те, що ви хочете тому що він буде точно визначити Місцезнаходження проблеми, і ви можете визначити об'єкт, що викликає це.

А. MsgBox в Catch, який відображається Error while... буде мало допомоги. Цей спосіб також призводить до дуже погано Запитання переповнення стеків, оскільки ви не можете описати фактичне виняток, об'єкт, що входить до нього, або навіть рядок коду, де це відбувається.

Ви також можете скористатись Locals Window (Налагодження -> Windows -> Локалі) для вивчення ваших об'єктів.

Як тільки ви знаєте, що та де ця проблема, зазвичай це досить легко виправити і швидше, ніж опублікувати нове запитання.

Дивись також:

Приклади та засоби захисту

Клас об'єкти / Створення екземпляра

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

Проблема полягає в тому, що Dim не створює CashRegister об'єкт; він оголошує лише змінну з ім'ям reg цього типу. Оголошуючи об'єктна змінна і створення екземпляр це дві різні речі.

Засіб усунення

The 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

Це створить a місцевий змінна reg, який існує лише в цьому контексті (підпункті). The reg змінна з модульним рівнем Scope який ви будете використовувати скрізь залишається Nothing.

Відсутній New Оператор є причиною №1 NullReference Exceptions розглянуті питання переповнення стека.

Visual Basic намагається спробувати процес кілька разів використовувати New: Використання New Оператор створює a новий об'єкт і дзвінки Sub New - конструктор - де ваш об'єкт може виконувати будь-яку іншу ініціалізацію.

Щоб бути зрозумілим, Dim (або Private) лише заявляє змінна та її Type. The Сфера застосування змінної - чи існує вона для всього модуля / класу або локально для процедури - визначається де це оголошено. 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, the 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

Використовуючи a 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

Обидва процедури призведуть до НРЕ, тому що 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 Объект набору даних був оголошений, але екземпляр ніколи не був створений. The DataAdapter заповнить існуючий DataSet, не створюй його. У цьому випадку, оскільки ds є локальною змінною IDE попереджає вас що це може статися:

img

При оголошенні як змінної рівня модуля / класу, як видається, є справа з con, компілятор не може знати, чи був об'єкт створено процедурою upstream. Не ігноруйте попередження.

Засіб усунення

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

The DataAdapter забезпечить TableNames як показано в попередньому прикладі, але він не аналізує імена з таблиці SQL або бази даних. В результаті, ds.Tables("TICKET_RESERVATION") посилання на неіснуючий таблицю.

The Засіб усунення те ж саме, посилання на таблицю за індексом:

If ds.Tables(0).Rows.Count > 0 Then

Дивись також Клас DataTable.


Пути об'єктів / вкладені

If myFoo.Bar.Items IsNot Nothing Then
   ...

Код перевіряється тільки Items хоча обидва myFoo і Bar може також бути нічим. The виправлення це тестування всієї ланцюга або шляху об'єктів по одному:

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")

Неможливо називати нічого "потік" a 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 призведе до НРЕ.

Засіб усунення

Перевірте дані перед використанням (також використовуйте 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

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 не існує в поточному контексті або "не може посилатися на нестатичний член". Отже, в якійсь мірі це є ситуація, коли тільки ВБ. Це також складно, оскільки це може спричинити несправність каскаду.

Масиви та колекції не можуть бути ініціалізовані таким чином. Цей код ініціалізації буде запущений раніше конструктор створює Form або Controls. В результаті:

  • Списки та збірка просто будуть порожніми
  • Масив міститиме п'ять елементів Nothing
  • The 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

Код масиву не може бути поза лісом. Будь-які елементи керування, які знаходяться в контейнері (наприклад, a GroupBox або Panel) не буде знайдено Me.Controls; вони будуть в колекції Controls цієї панелі або GroupBox. Також не буде повернуто контроль, коли ім'я контролера буде неправильно написано ("TeStBox2") У таких випадках Nothing буде знову зберігатися в цих елементах масиву, і NRE призведе до того, коли ви спробуєте вказати це.

Тепер вам слід легко знайти, що ви знаєте, що шукаєте: VS shows you the error of your ways

"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 попередить вас, що "не всі шляхи повертають значення і a 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 блок - ігровий майданчик диявола. Ця О.П. була здивована, чому він отримав NRE в Finally блок В інших ситуаціях порожній Catch може призвести до чогось іншого, що набагато далі вниз по течії, йде до того, що ви проводите час, дивлячись на неправильні речі в неправильному місці для цієї проблеми. ("Беззвучний виняток", описаний вище, забезпечує таку ж розважальну цінність.)

Засіб усунення

Не використовуйте порожні фільтри Try / Catch - нехай код аварійно завершує роботу, щоб ви могли визначити причину, б) визначити місце розташування, і в) застосувати належний засіб захисту. Блоки Try / Catch не призначені для приховування винятків від особи, яка має унікальну кваліфікацію для їх вирішення - розробника.


DBNull не такий самий, як нічого

For Each row As DataGridViewRow In dgvPlanning.Rows
    If Not IsDBNull(row.Cells(0).Value) Then
        ...

The IsDBNull Функція використовується для перевірки, якщо a вартість дорівнює System.DBNull: Від MSDN:

Значення System.DBNull вказує на те, що об'єкт представляє відсутні або неіснуючі дані. DBNull не співпадає з Nothing, що означає, що змінна ще не була ініціалізована.

Засіб усунення

If row.Cells(0) IsNot Nothing Then ...

Як і раніше, ви можете протестувати на Nothing, а потім на певне значення:

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

У ДГВ періодично спостерігаються кілька примх:

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.

Засіб усунення

Використовуйте a For/Each петлі і перевірити IsNewRow властивість визначити, чи це останній рядок. Це працює чи AllowUserToAddRows правда чи ні:

For Each r As DataGridViewRow in myDGV.Rows
    If r.IsNewRow = False Then
         ' ok to use this row

Якщо ви використовуєте a 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 колекцію потрібно буде лише ініціалізувати при першому запуску програми. Замінним засобом є додавання початкового значення до вашої колекції в Проект -> Налаштування | FooBars, збережіть проект, а потім видаліть підроблене значення.


Ключові моменти

Ви, напевно, забули New оператор

або

Щось, що ви припустили, буде виконувати бездоганно, щоб повернути ініціалізований об'єкт до вашого коду, чи ні.

Не ігноруйте попередження компілятора (будь-коли) і використовуйте Option Strict On (завжди).


Виняток MSDN NullReference


273





Інший сценарій полягає в тому, що ви відкидаєте нульовий об'єкт у a тип цінності. Наприклад, код нижче:

object o = null;
DateTime d = (DateTime)o;

Це кине а NullReferenceException на акті. Це здається цілком очевидним у наведеній вище вибірці, але це може статися в більш "пізньо пов'язаних" складних сценаріях, де нульовий об'єкт був повернутий з коду, який ви не володієте, а трансляція, наприклад, була згенерована деякою автоматичною системою.

Одним із прикладів цього є цей простий ASP.NET-зв'язувальний фрагмент за допомогою елемента керування календаря:

<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />

Тут SelectedDate насправді є власністю - DateTime тип - з Calendar Тип веб-керування, і прив'язка може відмінно повернути щось нульовим. Неявний генератор ASP.NET створить фрагмент коду, який буде еквівалентним коду, наведеному вище. І це підніме а NullReferenceException це досить важко визначити, оскільки воно полягає в сформованому коді ASP.NET, який компілює добре ...


217



Великий зловити. Однокласний спосіб уникнути: DateTime x = (DateTime) o as DateTime? ?? defaultValue; - Serge Shultz


Це означає, що ця змінна не вказана ні на що. Я міг згенерувати це так:

SqlConnection connection = null;
connection.Open();

Це викличе помилку, тому що, коли я оголосив змінну "connection", це не вказує на щось, коли я намагаюся назвати члена"Open", немає ніяких посилань на це для вирішення, і це буде кидати помилку.

Щоб уникнути цієї помилки:

  1. Завжди ініціалізуйте свої предмети, перш ніж намагатись щось робити з ними.
  2. Якщо ви не впевнені, чи є об'єкт нульовим, перевірте його object == null.

Інструмент Resarper JetBrains буде ідентифікувати кожен місце у вашому коді, який має можливість помилки нульової довідки, що дозволяє ввести нульову перевірку. Ця помилка являє собою номер один джерело помилок, IMHO.


146



Інструмент Resarper JetBrains буде ідентифікувати кожен місце у вашому коді, який має можливість помилки нульової довідки. Це неправильно. Я маю рішення без цього виявлення, але код іноді призводить до винятку. Я підозрюю, що іноді це не можна виявити - принаймні, - коли багатопоточність задіяна, але я не можу коментувати далі, оскільки ще не визначила місце мого помилки. - j riv
Але як це вирішити, коли NullReferenceException поставляється в usign HttpContext.Current.Responce.Clear (). Це не вирішується жодним з наведених вище рішень. тому що при створенні об'єкта об'єкта HttpContext з'являється помилка "Резервування перевантаження не вдалося, тому що недоступне" Нове "приймає це число аргументів. - Sunny Sandeep


Це означає, що у вашому коді використовувалася змінна посилання об'єкта, яка була встановлена ​​на нуль (тобто вона не посилалася на фактичний екземпляр об'єкта).

Щоб запобігти помилку, об'єкти, які можуть бути нульовими, повинні бути перевірені на нуль перед їх використанням.

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
}

135





Майте на увазі, що незалежно від сценарію, причина завжди однакова в .NET:

Ви намагаєтесь використовувати еталонну змінну, значення якої є Nothing/null. Коли значення є Nothing/null для еталонної змінної, тобто це фактично не містить посилання на екземпляр будь-якого об'єкта, який існує на купі.

Ви ніколи не призначили щось змінній, ніколи не створювали екземпляр значення, призначеного для змінної, або ви встановили змінну, яка дорівнює Nothing/null вручну, або ви викликали функцію, яка встановлює змінну до Nothing/null для вас


90





Прикладом цього виключення є те, що: коли ви намагаєтесь перевірити щось, це порожнє значення.

Наприклад:

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 і нульовий параметр.


76