0Pricing
C# Academy · Урок

Операторы условного объединения и объединения с null

Сочетайте ?., ?[], ?? и ??=, чтобы писать лаконичный безопасный относительно null код без громоздких проверок.

«Операторы условного объединения и объединения с null» — бесплатный урок C# Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.

Шаблоны безопасного кода при работе с null

C# предоставляет три специальных оператора для лаконичной работы со значениями null: условный оператор для null (?., ?[]), оператор объединения с null (??) и оператор присваивания с объединением по null (??=). Вместе они устраняют большую часть громоздкого шаблонного кода для проверок на null.

Условный оператор для null: ?.

?. возвращает null, если левая часть равна null, вместо того чтобы выбрасывать NullReferenceException. Тип результата становится допускающим null.

User? user = GetUser(id);

// Without ?.:
string? name = null;
if (user != null) name = user.Name;

// With ?.:
string? name2 = user?.Name;

// Chained:
string? city = user?.Address?.City;

// Method call:
string? upper = user?.Name?.ToUpper();

Условный оператор для null с индексатором: ?[]

?[] — это условный оператор доступа по индексу для null. Он безопасно обращается к элементам массива или коллекции, если сама коллекция может быть равна null.

List<string>? tags = product?.Tags;

// Safe index access
string? firstTag = tags?[0];

// Null-conditional LINQ
int? count = tags?.Count;
bool? hasItems = tags?.Any();

// With methods:
string? joined = tags?.FirstOrDefault()?.ToUpper();

Оператор объединения с null: ??

?? возвращает левый операнд, если он не равен null, а в противном случае возвращает правый операнд (резервный вариант). Это лаконичная замена конструкции x != null ? x : fallback.

string? name = GetName();

// Without ??:
string display = name != null ? name : "Anonymous";

// With ??:
string display2 = name ?? "Anonymous";

// Chaining ?? for multiple fallbacks:
string result = primary ?? secondary ?? tertiary ?? "Default";

// Combining with ?.
string city = user?.Address?.City ?? "Unknown City";

Присваивание с объединением по null: ??=

??= присваивает правую часть переменной, только если переменная в данный момент равна null. Этот оператор отлично подходит для шаблонов ленивой инициализации.

// Lazy initialization
private List<string>? _cache;

public List<string> GetCache()
{
    _cache ??= new List<string>(); // only assigns if null
    return _cache;
}

// Equivalent to:
// if (_cache is null) _cache = new List<string>();

// In-place:
string? name = null;
name ??= "Default";
Console.WriteLine(name); // "Default"

Использование ?. с событиями

null-условный оператор — стандартный потокобезопасный способ вызвать событие: он устраняет состояние гонки, возникающее при раздельной проверке на null и вызове.

public event EventHandler<DataEventArgs>? DataReceived;

// Thread-safe event invocation:
DataReceived?.Invoke(this, new DataEventArgs(data));

// This is equivalent to:
var handler = DataReceived;
if (handler != null) handler(this, new DataEventArgs(data));
// (local copy avoids race condition between check and invoke)

Сложные примеры цепочек

Комбинирование операторов позволяет чисто и понятно перемещаться по графам глубоко вложенных объектов, безопасно обрабатывая null.

var order = GetOrder(id);

// Deeply nested with fallbacks:
string countryCode = order
    ?.Customer
    ?.ShippingAddress
    ?.Country
    ?.Code
    ?? "US";

// Collection safe access:
decimal firstLineTotal = order
    ?.Lines
    ?.FirstOrDefault()
    ?.Total
    ?? 0m;

// Method chain:
string? trackingUpper = order?.TrackingNumber?.ToUpper().Trim();

null-условный оператор в LINQ

null-условный оператор без проблем работает с LINQ, позволяя безопасно выполнять запросы к коллекциям или свойствам, которые могут содержать null.

List<Order>? orders = customer?.Orders;

// Safe LINQ on a nullable collection:
var totalRevenue = orders?.Sum(o => o.Total) ?? 0m;
var pendingCount = orders?.Count(o => o.Status == OrderStatus.Pending) ?? 0;
var latest       = orders?.MaxBy(o => o.PlacedAt)?.Id;

Защита от null с помощью ThrowIfNull

Для параметров, которые не должны быть равны null, используйте ArgumentNullException.ThrowIfNull() (.NET 6+), чтобы кратко и понятно выполнять проверку в начале метода.

public void ProcessOrder(Order order, Customer customer)
{
    ArgumentNullException.ThrowIfNull(order);
    ArgumentNullException.ThrowIfNull(customer);

    // From this point, compiler knows both are non-null
    Console.WriteLine(order.Id);
    Console.WriteLine(customer.Name);
}

// .NET 7+: ArgumentException.ThrowIfNullOrEmpty
void Save(string name)
{
    ArgumentException.ThrowIfNullOrWhiteSpace(name);
    // name is guaranteed non-empty
}

Шаблон проверки на отсутствие null в switch

Сопоставление с образцом с помощью is not null и is { } обеспечивает чистые шаблоны проверки на null, особенно в выражениях switch.

string Describe(object? obj) => obj switch
{
    null                          => "nothing",
    string s when s.Length == 0  => "empty string",
    string s                      => $"string: {s}",
    int i                         => $"integer: {i}",
    { }                           => $"object: {obj.GetType().Name}"
};

// is not null in if statements:
if (order is not null && order.Customer is { Name: var name })
    Console.WriteLine(name);

Быстрая проверка

Что возвращает выражение user?.Name ?? "Anonymous", если user равен null?

Повторение: null-условный оператор и оператор объединения по null

Основные выводы:

  • ?.: безопасный доступ к члену — возвращает null вместо исключения, если объект-получатель равен null
  • ?[]: безопасный доступ по индексу к коллекциям, которые могут быть равны null
  • ??: резервное значение, если левый операнд равен null
  • ??=: присваивание только при значении null — идеально для ленивой инициализации
  • Объединяйте их в цепочки: a?.B?.C ?? defaultVal для безопасного доступа к глубоко вложенным объектам
  • ArgumentNullException.ThrowIfNull() для защиты параметров с помощью проверки

Часто задаваемые вопросы

Урок «Операторы условного объединения и объединения с null» бесплатный?

Да — полный текст урока «Операторы условного объединения и объединения с null» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.

Чему я научусь в уроке «Операторы условного объединения и объединения с null»?

Сочетайте ?., ?[], ?? и ??=, чтобы писать лаконичный безопасный относительно null код без громоздких проверок. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C# Academy?

Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Операторы условного объединения и объединения с null»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C# Academy?

Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Включение и понимание NRT
  2. Аннотации: ?, !, MaybeNull и NotNull
  3. Операторы условного объединения и объединения с null
  4. Перенос кодовой базы на NRT
← Назад к C# Academy