NullReferenceException в C#: как найти и исправить ошибку

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое NullReferenceException и как с ним бороться? Полный гайд для C# разработчика

Вы когда-нибудь видели это страшное сообщение: “Object reference not set to an instance of an object”? Если вы пишете на C# хотя бы неделю, то наверняка сталкивались. Это NullReferenceException — самая популярная ошибка в мире .NET. Она пугает новичков, но опытные разработчики знают: это просто способ программы сказать “Я не знаю, с чем работать, дай мне объект”.

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

Что такое NullReferenceException простыми словами?

Представьте, что вы заказали пиццу, а курьер пришёл с пустыми руками. Вы спрашиваете: “Где моя пицца?”, а он отвечает: “Я не знаю, у меня ничего нет”. Примерно так же работает NullReferenceException. Вы пытаетесь вызвать метод или обратиться к свойству переменной, которая равна null. Компилятор этого не видит, но во время выполнения программа падает.

В C# любая ссылочная переменная (класс, интерфейс, строка, массив) может быть null. Если вы попытаетесь сделать что-то с такой переменной, получите исключение.

Самые частые сценарии возникновения NullReferenceException

Давайте посмотрим на реальные примеры кода, которые приводят к этой ошибке.

1. Неинициализированная переменная

string name;
Console.WriteLine(name.Length); // NullReferenceException

Переменная name объявлена, но не инициализирована. По умолчанию она равна null.

2. Метод возвращает null

public string GetUserName(int id)
{
    // если пользователь не найден, возвращаем null
    return null;
}

var user = GetUserName(42);
Console.WriteLine(user.ToUpper()); // NullReferenceException

3. Доступ к элементу коллекции, которого нет

var list = new List<string> { "A", "B" };
var item = list[5]; // ArgumentOutOfRangeException, но если бы элемент был null...
// А вот пример с Dictionary:
var dict = new Dictionary<int, string>();
var value = dict[1]; // KeyNotFoundException, но если бы ключ существовал, а значение было null?

4. Цепочка вызовов

class Address { public string City { get; set; } }
class Person { public Address Address { get; set; }

var person = new Person();
Console.WriteLine(person.Address.City); // NullReferenceException, потому что Address == null

Как найти NullReferenceException: отладка для начинающих

Когда программа падает, Visual Studio или Rider покажут стек вызовов. Там будет строка, где произошла ошибка. Но часто проблема глубже. Вот алгоритм поиска:

  • Посмотрите на строку с ошибкой. Какая переменная там используется? Она точно не null?
  • Проверьте, откуда пришло значение. Если это результат метода — посмотрите, может ли он вернуть null.
  • Используйте точки остановки. Поставьте breakpoint перед строкой с ошибкой и проверьте значения всех переменных.
  • Добавьте условные точки остановки. В Visual Studio можно поставить breakpoint с условием: myVar == null.

Как исправить NullReferenceException: 5 проверенных способов

Хорошая новость: NullReferenceException почти всегда можно предотвратить. Вот что вы можете сделать.

1. Проверка на null (старый добрый if)

if (name != null)
{
    Console.WriteLine(name.Length);
}
else
{
    Console.WriteLine("Имя не задано");
}

Это работает, но делает код громоздким, если проверок много.

2. Оператор условного доступа (?.)

Современный C# (начиная с версии 6) предлагает элегантное решение — null-conditional operator:

int? length = name?.Length; // если name == null, length будет null
Console.WriteLine(length ?? 0); // выведет 0, если name == null

Этот оператор ?. проверяет: если объект не null, то вызови метод/свойство; если null — верни null.

3. Оператор объединения с null (??)

string displayName = name ?? "Гость"; // если name == null, используем "Гость"
Console.WriteLine(displayName);

Отлично работает вместе с ?. :

Console.WriteLine(name?.ToUpper() ?? "N/A");

4. Проверка аргументов методов

public void ProcessData(string data)
{
    if (data == null)
        throw new ArgumentNullException(nameof(data));
    // дальше работаем с data, зная что она не null
}

Это защищает ваш метод от неверных входных данных.

5. Использование nullable-контекста (C# 8+)

Начиная с C# 8, вы можете включить nullable reference types. Это заставит компилятор предупреждать о потенциальных null:

#nullable enable
string name = null; // предупреждение компилятора!
string? nullableName = null; // OK, мы явно указали, что может быть null

Включите эту опцию в проекте — и многие NullReferenceException будут пойманы ещё на этапе компиляции.

Лучшие практики: как избежать NullReferenceException навсегда

Вот несколько принципов, которые помогут вам писать код, устойчивый к null:

  • Инициализируйте переменные сразу. Вместо string name; пишите string name = string.Empty; или string name = "";
  • Не возвращайте null из методов. Лучше вернуть пустую коллекцию (Enumerable.Empty<T>()) или выбросить исключение с понятным сообщением.
  • Используйте паттерн “Null Object”. Вместо null создайте объект-заглушку с безопасным поведением.
  • Проверяйте внешние данные. Всё, что приходит из БД, API или от пользователя, может быть null.
  • Включите nullable-контекст. Это лучшая инвестиция в качество кода.

Пример из реальной жизни: исправляем баг

Представьте, что у вас есть метод, который получает данные о пользователе и выводит его город:

public void PrintUserCity(int userId)
{
    var user = GetUserFromDatabase(userId);
    Console.WriteLine(user.Address.City); // потенциальный NullReferenceException
}

Исправляем:

public void PrintUserCity(int userId)
{
    var user = GetUserFromDatabase(userId);
    var city                

Блоги

Рекомендаций по книгам