Классы в C#, как известно, относятся к ссылочным типам данных. Отличием ссылочных типов от типов значений состоит в том, что переменные ссылочных типов могут принимать значение null
. Сегодня мы поговорим подробно про это значение в C# и о том, как можно осуществить проверку на null
объектов C#.
Как известно, строки в C# также относятся к классам, поэтому обе представленных ниже операции могут быть выполнены без ошибок компиляции:
object o = null; string s = null;
Если мы объявим переменную ссылочного типа и не присвоим её никакого значения, то по умолчанию такой переменной будет присвоено значение null
, что будет фактически говорить о том, что переменной значение не присвоено. При этом, типы значений не могут принимать значение null
, например, следующий код приведет к ошибке:
double d = null;
Оператор ??
Про этот оператор мы не говорили, когда разбирали логические операторы C#. Оператор ??
называется оператором null-объединения. Обычно, оператор null-объединения используется для того, чтобы установить для переменных ссылочного типа значение по умолчанию.
Принцип действия оператора null-объекдинения: оператор ??
возвращает левый операнд, если этот операнд не равен null
. Иначе вычисляется правый операнд и возвращается его значение. То есть, слева от ??
всегда должна быть переменная ссылочного типа, т.е. «уметь» принимать значение null
, например:
object x = null; object y = x ?? "Переменной X присвоено значение null"; Console.WriteLine(y); object z = 200; object t = z ?? 44; //значение t = 200 Console.WriteLine(t);
В примере с объектов x
на экран будет выведена строка «Переменной X присвоено значение null
» так как x
у нас равен null
. Во втором случае, с переменной z
на экран будет выведено значение 200
так как переменной z
присвоено значение отличное от null
.
При этом, мы не можем выполнить такую проверку:
int x = 44; int y = x ?? 100;
Visual Studio сразу выдаст ошибку:
Здесь переменная x
представляет тип значений (int
) и не может принимать значение null
, поэтому в качестве левого операнда в операции ??
она использоваться не может.
Оператор условного null
При работе с объектами, которые принимают значение null
, довольно часто (особенно новички), могут столкнуться со следующей ошибкой: попытка обратиться к объекту вызывает ошибку, так как этот объект фактически равен null
. Например, пусть у нас есть следующая система классов:
class User { public Phone Phone { get; set; } } class Phone { public Company Company { get; set; } } class Company { public string Name { get; set; } }
Здесь объект User
содержит ссылку на объект Phone
, который, в свою очередь, содержит ссылку на объект Company
. Теоретически, мы можем получить из объекта User
название компании, например:
User user = new User(); Console.WriteLine(user.Phone.Company.Name);
Так как мы использовали конструктор по умолчанию, то свойство Phone
не определено (имеет значение null
) и, соответственно, Company
тоже равно null
. Поэтому, если мы попытаемся получить значение Company
, то столкнемся с исключением NullReferenceException
. Чтобы избежать такой ошибки мы могли бы использовать условный оператор if
для проверки на null
свойств у User
и Phone
, например:
User user = new User(); if(user!=null) { if(user.Phone!=null) { if (user.Phone.Company != null) { string companyName = user.Phone.Company.Name; Console.WriteLine(companyName); } } }
В итоге код будет работать, исключения не возникнет, но многоуровневая конструкция с нагромождением if
наш код не красит, поэтому её можно сократить и написать вот так, используя наши знания по логическим операциям C#:
if(user!=null && user.Phone!=null && user.Phone.Company!=null) { string companyName = user.Phone.Company.Name; Console.WriteLine(companyName); }
Здесь мы уже задействовали условное логическое И. Конструкция, в итоге, получилась намного проще, но все равно довольно большой. Чтобы ее упростить, в C# имеется оператор условного null:
string companyName = user?.Phone?.Company?.Name;
Выражение ?.
— это оператор условного null. В коде выше последовательно проверяется равен ли объект user
и вложенные объекты значению null
и, если на каком-то этапе один из объектов окажется равным null
, то companyName
будет иметь значение по умолчанию, то есть null
. Опять же, чтобы не получать в итоге на выходе null
, можно объединить операторы ??
и ?.
и написать проверку следующим образом:
User user = new User(); string companyName = user?.Phone?.Company?.Name ?? "не установлено"; Console.WriteLine(companyName);
Оператор ??=
Начиная с C# 8.0 можно использовать оператор присваивания объединения (=
) со значением null
.
Оператор ??=
используется для присваивания значения правого операнда левому только в том случае, если левый операнд принимает значение null
.
Оператор ??=
не выполняет оценку своего операнда справа, если его операнд слева имеет значение, отличное от null
. Например:
List<int> numbers = null; (numbers ??= new List<int>()).Add(5); Console.WriteLine(numbers[0]);
Так как объект numbers
имел значение null
, то, при использовании оператора ??=
будет создан объект типа List<int>
и в список будет добавлено число 5
.
Итого
Сегодня мы узнали о значении null
и как проводить проверки на null
различных объектов ссылочного типа, а также узнали про относительно новый оператор ??=
с помощью которого можно присваивать значение объектам ссылочного типа в том случае, если они равны null
.