Проверка на null, операторы ?. и ??

Последнее обновление: 11.11.2021

Проверка на null. Null guard

Если мы собираемся использовать переменную или параметр, которые допускают значение null, то есть представляют nullable-тип (не важно значимый или ссылочный), то, чтобы избежать возникновения NullReferenceException, мы можем проверить на null:

void PrintUpper(string? text)
{
    if (text!=null)
    {
        Console.WriteLine(text.ToUpper());
    }    
}

В данном случае если параметр text не равен null, то вызываем у строки метод ToUpper(), который переводит символы строки в верхний регистр.

Кроме того, с помощью оператора is мы можем проверить значение объекта:

объект is значение

Если объект слева от оператора is имеет значение справа от оператора. тогда оператор is возвращает true, иначе возвращается false

Например, проверка параметра/переменной на значение null:

void PrintUpper(string? text)
{
    if (text is  null) return;
    Console.WriteLine(text.ToUpper());
}

Или, наоборот, с помощью is not можно проверить отсутствие значения:

void PrintUpper(string? text)
{
    if (text is not null) 
		Console.WriteLine(text.ToUpper());
}

Также можно проверить на соответствие типу, значение которого мы собираемся использовать:

void PrintUpper(string? text)
{
    if (text is string)
        Console.WriteLine(text.ToUpper());
    else 
        Console.WriteLine("NULL");
}

Подобные проверки еще называются null guard или условно говоря "защита от null".

Оператор ??

Оператор ?? называется оператором null-объединения. Он применяется для установки значений по умолчанию для типов, которые допускают значение null:

левый_операнд ?? правый_операнд

Оператор ?? возвращает левый операнд, если этот операнд не равен null. Иначе возвращается правый операнд. При этом левый операнд должен принимать null. Посмотрим на примере:

string? text = null;
string name = text ?? "Tom";  // равно Tom, так как text равен null
Console.WriteLine(name);	// Tom

int? id = 200;
int personid = id ?? 1; // равно 200, так как id не равен null
Console.WriteLine(personid);	// 200

Но мы не можем написать следующим образом:

int x = 44;
int y = x ?? 100;

Здесь переменная x представляет значимый тип int и не может принимать значение null, поэтому в качестве левого операнда в операции ?? она использоваться не может.

Также можно использовать производный оператора ??=

string? text = null;
text ??= "Sam";
// аналогично
// text = text ?? "Sam";
Console.WriteLine(text);    // Sam

int? id = 100;
id ??= 1;
// аналогично
//id = id ?? 1;
Console.WriteLine(id); // 100

Оператор условного null

Иногда при работе с объектами, которые принимают значение null, мы можем столкнуться с ошибкой: мы пытаемся обратиться к объекту, а этот объект равен null. Например, пусть у нас есть следующая система классов:

class Person
{
    public Company? Company { get; set; }   // место работы
}
class Company
{
    public string? WebSite { get; set; }    // веб-сайт компании
}

Объект Person представляет человека. Его свойство Company представляет компанию, где человек работает. Но человек может не работать, поэтому свойство Company имеет тип Company?, то есть может иметь значение null.

Класс Company в свою очередь содержит свойство WebSite, которое представляет веб-сайт компании. Но у компании может и не быть собственного веб-сайта. Поэтому это свойство имеет тип string?, то есть также допускает значение null.

Допустим, нам надо вывести на консоль заглавными буквами веб-сайт компании, где работает человек (если он, конечно, работает и если у компании, где он работает, есть сайт). На первый взгляд мы можем написать следующую конструкцию:

void PrintWebSite(Person? person)
{
    if (person != null)
    {
        if(person.Company != null)
        {
            if(person.Company.WebSite != null)
            {
                Console.WriteLine(person.Company.WebSite.ToUpper());
            }
        }
    }
}
class Person
{
    public Company? Company { get; set; }   // место работы
}
class Company
{
    public string? WebSite { get; set; }    // веб-сайт компании
}

В методе PrintWebSite() принимаем объект Person? и, чтобы избежать исключения NullReferenceException, последовательно проверяем все используемые значения на null, чтобы в конце с помощью метода ToUpper() вывести заглавными буквами название сайта.

Хоть это и рабочий способ, но для простого вывода строки получается многоэтажная конструкция, но на самом деле ее можно сократить:

void PrintWebSite(Person? person)
{
    if (person != null && person.Company != null && person.Company.WebSite != null)
    {
        Console.WriteLine(person.Company.WebSite.ToUpper());
    }
}

Конструкция намного проще, но все равно получается довольно большой. И чтобы ее упростить, в C# есть оператор условного null (Null-Conditional Operator) - оператор ?.:

объект?.компонент

Если объект не равен null, то происходит обращение к компоненту объекта - полю, свойству, методу. Если объект представляет значение null, обращение к компаненту метода не происходит.

Применим данный оператор, изменив предыдущий пример:

void PrintWebSite(Person? person)
{
    Console.WriteLine(person?.Company?.WebSite?.ToUpper());
}

Таким образом, если person не равен null, то происходит обращение к его свойству Company. Если свойство Company не равно null, то идет обрашение к свойству WebSite объекта Company. Если свойство WebSite не равно null, то идет обращение к методу ToUpper().

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850