Классы в 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.