Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен
Шрифт:
Интервал:
Закладка:
nullableInt ??= 14;
Console.WriteLine(nullableInt);
Сначала переменная nullableInt инициализируется значением null. В следующей строке переменной nullableInt присваивается значение 12, поскольку левый операнд действительно равен null. Но в следующей за ней строке переменной nullableInt не присваивается значение 14, т.к. она не равна null.
null-условная операция
При разработке программного обеспечения обычно производится проверка на предмет null входных параметров, которым передаются значения, возвращаемые членами типов (методами, свойствами, индексаторами). Например, пусть имеется метод, который принимает в качестве единственного параметра строковый массив. В целях безопасности его желательно проверять на предмет null, прежде чем начинать обработку. Поступая подобным образом, мы не получим ошибку во время выполнения, если массив окажется пустым. Следующий код демонстрирует традиционный способ реализации такой проверки:
static void TesterMethod(string[] args)
{
// Перед доступом к данным массива мы должны проверить его
// на равенство null!
if (args != null)
{
Console.WriteLine($"You sent me {args.Length} arguments.");
// Вывод количества аргументов
}
}
Чтобы устранить обращение к свойству Length массива string в случае, когда он равен null, здесь используется условный оператор. Если вызывающий код не создаст массив данных и вызовет метод TesterMethod() примерно так, как показано ниже, то никаких ошибок во время выполнения не возникнет:
TesterMethod(null);
В языке C# имеется маркер null-условной операции (знак вопроса, находящийся после типа переменной, но перед операцией доступа к члену), который позволяет упростить представленную ранее проверку на предмет null. Вместо явного условного оператора, проверяющего на неравенство значению null, теперь можно написать такой код:
static void TesterMethod(string[] args)
{
// Мы должны проверять на предмет null перед доступом к данным массива!
Console.WriteLine($"You sent me {args?.Length} arguments.");
}
В этом случае условный оператор не применяется. Взамен к переменной массива string в качестве суффикса добавлена операция ?. Если переменная args равна null, тогда обращение к свойству Length не приведет к ошибке во время выполнения. Чтобы вывести действительное значение, можно было бы воспользоваться операцией объединения с null и установить стандартное значение:
Console.WriteLine($"You sent me {args?.Length ?? 0} arguments.");
Существуют дополнительные области написания кода, в которых null-условная операция окажется очень удобной, особенно при работе с делегатами и событиями. Данные темы раскрываются позже в книге (см. главу 12) и вы встретите еще много примеров.
Понятие кортежей (нововведение и обновление в версии 7.0)
В завершение главы мы исследуем роль кортежей, используя проект консольного приложения по имени FunWithTuples. Как упоминалось ранее в главе, одна из целей применения параметров out — получение более одного значения из вызова метода. Еще один способ предусматривает использование конструкции под названием кортежи.
Кортежи, которые являются легковесными структурами данных, содержащими множество полей, фактически появились в версии C# 6, но применяться могли в крайне ограниченной манере. Кроме того, в их реализации C# 6 существовала значительная проблема: каждое поле было реализовано как ссылочный тип, что потенциально порождало проблемы с памятью и/или производительностью (из-за упаковки/распаковки).
В версии C# 7 кортежи вместо ссылочных типов используют новый тип данных ValueTuple, сберегая значительных объем памяти. Тип данных ValueTuple создает разные структуры на основе количества свойств для кортежа. Кроме того, в C# 7 каждому свойству кортежа можно назначать специфическое имя (подобно переменным), что значительно повышает удобство работы с ними.
Относительно кортежей важно отметить два момента:
• поля не подвергаются проверке достоверности;
• определять собственные методы нельзя.
В действительности кортежи предназначены для того, чтобы служить легковесным механизмом передачи данных.
Начало работы с кортежами
Итак, достаточно теории, давайте напишем какой-нибудь код! Чтобы создать кортеж, просто повестите значения, подлежащие присваиванию, в круглые скобки:
("a", 5, "c")
Обратите внимание, что все значения не обязаны относиться к тому же самому типу данных. Конструкция с круглыми скобками также применяется для присваивания кортежа переменной (или можно использовать ключевое слово var и тогда компилятор назначит типы данных самостоятельно). Показанные далее две строки кода делают одно и то же — присваивают предыдущий пример кортежа переменной. Переменная values будет кортежем с двумя свойствами string и одним свойством int.
(string, int, string) values = ("a", 5, "c");
var values = ("a", 5, "c");
По умолчанию компилятор назначает каждому свойству имя ItemX, где X представляет позицию свойства в кортеже, начиная с 1. В предыдущем примере свойства именуются как Item1, Item2 и Item3. Доступ к ним осуществляется следующим образом:
Console.WriteLine($"First item: {values.Item1}"); // Первый элемент
Console.WriteLine($"Second item: {values.Item2}"); // Второй элемент
Console.WriteLine($"Third item: {values.Item3}"); // Третий элемент
Кроме того, к каждому свойству кортежа справа или слева можно добавить специфическое имя. Хотя назначение имен в обеих частях оператора не приводит к ошибке на этапе компиляции, имена в правой части игнорируются, а использоваться будут имена в левой части. Показанные ниже две строки кода демонстрируют установку имен в левой и правой частях оператора, давая тот же самый результат:
(string FirstLetter, int TheNumber, string SecondLetter)
valuesWithNames = ("a", 5, "c");
var valuesWithNames2 = (FirstLetter: "a", TheNumber: 5, SecondLetter: "c");
Теперь доступ к свойствам кортежа возможен с применением имен полей, а также системы обозначений ItemX:
Console.WriteLine($"First item: {valuesWithNames.FirstLetter}");
Console.WriteLine($"Second item: {valuesWithNames.TheNumber}");
Console.WriteLine($"Third item: {valuesWithNames.SecondLetter}");
// Система обозначений ItemX по-прежнему работает!
Console.WriteLine($"First item: {valuesWithNames.Item1}");
Console.WriteLine($"Second item: {valuesWithNames.Item2}");
Console.WriteLine($"Third item: {valuesWithNames.Item3}");
Обратите внимание, что при назначении имен в правой части оператора должно использоваться ключевое слово var для объявления переменной. Установка типов данных специальным образом (даже без специфических имен) заставляет компилятор применять синтаксис в левой части оператора, назначать свойствам имена согласно системе обозначений ItemX и игнорировать имена, указанные в правой части. В следующих двух операторах имена Custom1 и Custom2 игнорируются:
(int, int) example = (Custom1:5, Custom2:7);
(int Field1, int Field2) example = (Custom1:5, Custom2:7);
Важно также понимать,