Avatar ·

Что такое NullReferenceException в C# и как её исправить?

Всем привет! Я новичок в C# и постоянно натыкаюсь на ошибку NullReferenceException. Она возникает у меня в самых неожиданных местах, и я не понимаю, что я делаю не так. Вот пример кода, который у меня падает: ```csharp public class Person { public string Name; public int Age; } class Program { static void Main(string[] args) { Person person = null; Console.WriteLine(person.Name); // Здесь вылетает NullReferenceException } } ``` Я просто хочу вывести имя человека, но программа крашится. Почему это происходит? Я слышал, что это связано с тем, что объект равен null, но как это понять? Может быть, я неправильно создаю объекты? Или нужно проверять что-то перед использованием? Подскажите, пожалуйста, как правильно работать с null в C# и как избегать этой ошибки. Буду благодарен за подробное объяснение с примерами, так как я только начинаю разбираться в языке. <<>>

Что такое NullReferenceException?

NullReferenceException (исключение нулевой ссылки) — это ошибка, которая возникает, когда вы пытаетесь обратиться к члену (методу, свойству, полю) объекта, который равен null. В C# null означает «отсутствие объекта» или «пустую ссылку». Если вы попытаетесь вызвать что-то у такой ссылки, среда выполнения (CLR) не сможет выполнить операцию и выбросит это исключение.

В вашем примере:

Person person = null;
Console.WriteLine(person.Name); // Ошибка!

Переменная person не ссылается ни на какой реальный объект в памяти. Когда вы пишете person.Name, программа пытается найти поле Name у несуществующего объекта — отсюда и исключение.

Как исправить? Основные методы

1. Инициализируйте объекты перед использованием

Самый простой способ — убедиться, что объект создан:

Person person = new Person(); // Создаём объект
person.Name = "Иван";
Console.WriteLine(person.Name); // Выведет "Иван"

2. Проверяйте на null

Если объект может быть null (например, возвращается из метода или передаётся как параметр), всегда проверяйте его перед использованием:

if (person != null)
{
    Console.WriteLine(person.Name);
}
else
{
    Console.WriteLine("Объект person равен null");
}

3. Используйте операторы для работы с null (C# 6+ и C# 8+)

Современный C# предлагает удобные операторы для сокращения кода:

  • Оператор условного null (?.) — безопасно обращается к члену, если объект не null:
Console.WriteLine(person?.Name); // Если person == null, выведет пустую строку (без ошибки)
  • Оператор объединения с null (??) — задаёт значение по умолчанию, если объект null:
string name = person?.Name ?? "Неизвестно";
Console.WriteLine(name); // Если person == null, выведет "Неизвестно"

4. Включайте nullable-контекст (C# 8+)

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

#nullable enable
Person? person = null; // '?' означает, что person может быть null
// Компилятор предупредит, если вы попытаетесь обратиться к person.Name без проверки

Типичные сценарии возникновения ошибки

  • Коллекции: попытка доступа к элементу неинициализированного списка или массива.
  • Методы, возвращающие null: например, FirstOrDefault() для пустой коллекции.
  • События: вызов события без проверки на null.
  • Вложенные объекты: person.Address.City — если Address равен null.

Как отлаживать?

Когда вы видите NullReferenceException в стеке вызовов, посмотрите на строку кода, где произошла ошибка. Определите, какой именно объект равен null. Используйте отладчик (точки остановки) или добавьте проверки if (obj == null) Console.WriteLine("obj is null");.

Главное правило: всегда инициализируйте объекты или проверяйте их на null перед использованием. Со временем вы научитесь предвидеть такие ситуации и писать более надёжный код.

<<>>

Альтернативный подход: Использование шаблона "Null Object"

Иногда вместо постоянных проверок на null можно использовать специальный объект-заглушку, который реализует то же поведение, но не вызывает ошибок. Это называется шаблоном "Null Object".

Пример для вашего класса Person:

public class Person
{
    public string Name { get; set; } = "Неизвестно";
    public int Age { get; set; } = 0;
    
    public static Person Null { get; } = new Person(); // Объект-заглушка
}

// Использование:
Person person = GetPersonFromDatabase(); // Может вернуть null
person = person ?? Person.Null; // Если null, используем заглушку
Console.WriteLine(person.Name); // Безопасно

Этот подход особенно полезен, когда у вас много мест, где потенциально может быть null, и вы хотите избежать раздувания кода проверками. Однако будьте осторожны: заглушка не должна скрывать реальные проблемы (например, когда null означает ошибку). Используйте его только там, где "пустое" значение является допустимым сценарием.

Также в C# 8+ можно использовать nullable-аннотации для явного указания, может ли переменная быть null. Это помогает компилятору предупреждать вас о потенциальных проблемах на этапе компиляции, а не в рантайме.