5 новинок в C#10

Многим интересно, в каком направлении будет идти развитие C# 10. Возможности не секрет. Стоит потратить немного времени на страницу C # в  GitHub, и вы найдете длинный список дразнящих идей, некоторые из которых еще не решены. Многие из них не войдут в следующую версию C #, а некоторые вообще не появятся в языке. (Существует высокая планка, чтобы попасть в C #, потому что язык требует, чтобы после поддержки ключевого слова или синтаксической структуры его поведение никогда не изменялось критически.)

Если вам интересно, какие функции гарантированно окажутся в новой версии языка, вы можете подождать, пока язык будет выпущен в ноябре вместе с .NET 6. Или вы можете следить людьми из команды C #, которые демонстрируют свои любимые функции. На прошлой неделе на конференции Microsoft Build ведущий разработчик C # Мэдс Торгерсен приоткрыл завесу с некоторых работ, которые в настоящее время ведутся. Вот пять новых функций, которые вы увидите в следующем выпуске языка.

1. Глобальные using

Обычно, файл исходного кода C# начинается с портянки перечислений используемых пространств имен. Вот фрагмент кода обычного файла веб приложения ASP .NET:

[pastacode lang=»c» manual=»using%20LoggingTestApp.Data%3B%0Ausing%20Microsoft.AspNetCore.Builder%3B%0Ausing%20Microsoft.AspNetCore.Hosting%3B%0Ausing%20Microsoft.AspNetCore.HttpsPolicy%3B%0Ausing%20Microsoft.AspNetCore.Identity%3B%0Ausing%20Microsoft.AspNetCore.Identity.UI%3B%0Ausing%20Microsoft.EntityFrameworkCore%3B%0Ausing%20Microsoft.Extensions.Configuration%3B%0Ausing%20Microsoft.Extensions.DependencyInjection%3B%0Ausing%20Microsoft.Extensions.Hosting%3B%0Ausing%20Serilog%3B%0Ausing%20System%3B%0Ausing%20System.Collections.Generic%3B%0Ausing%20System.Linq%3B%0Ausing%20System.Threading.Tasks%3Bnamespace%20LoggingTestApp%0A%7B%0A%20%20%20%20public%20class%20Startup%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20…%0A%20%20%20%20%7D%0A%7D» message=»» highlight=»» provider=»manual»/]

Нет ничего необычного. Но когда-то давно импорт пространства имен дал нам быстрое представление о том, какие библиотеки использует класс. Сегодня это стало еще одним шаблоном, который мы обычно прокручиваем и не берем во внимание при изучении или написании кода.

В C# 10 представлен новый шаблон, который позволяет определять импорт пространства имен для всего проекта с помощью ключевого слова global. Рекомендуется помещать глобальный импорт в отдельный файл (по одному для каждого проекта), возможно, с именем usings.cs или imports.cs. Вот как это может выглядеть:

[pastacode lang=»c» manual=»global%20using%20Microsoft.AspNetCore.Builder%3B%0Aglobal%20using%20Microsoft.AspNetCore.Hosting%3B%0Aglobal%20using%20Microsoft.AspNetCore.HttpsPolicy%3B%0Aglobal%20using%20Microsoft.AspNetCore.Identity%3B%0Aglobal%20using%20Microsoft.AspNetCore.Identity.UI%3B%0Aglobal%20using%20Microsoft.EntityFrameworkCore%3B%0Aglobal%20using%20Microsoft.Extensions.Configuration%3B%0Aglobal%20using%20Microsoft.Extensions.DependencyInjection%3B%0Aglobal%20using%20Microsoft.Extensions.Hosting%3B%0Aglobal%20using%20System%3B%0Aglobal%20using%20System.Collections.Generic%3B%0Aglobal%20using%20System.Linq%3B%0Aglobal%20using%20System.Threading.Tasks%3B» message=»» highlight=»» provider=»manual»/]

Теперь можно упростить файл с исходным кодом написав лишь одну строку using:

[pastacode lang=»c» manual=»using%20LoggingTestApp.Data%3B%0Ausing%20Serilog%3Bnamespace%20LoggingTestApp%0A%7B%0A%20%20%20%20public%20class%20Startup%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20…%0A%20%20%20%20%7D%0A%7D» message=»» highlight=»» provider=»manual»/]

Visual Studio выделяет дублирующиеся пространства имен (импортируемые глобально и локально в файл). Хотя это не ошибка, удаление повторяющихся пространств имен позволяет сократить объем стандартного кода и сосредоточить внимание на специальных пространствах имен, которые использует конкретный файл.

2. Пространства имен файловой области

Другой способ упростить ваш код на C# 10 — объявить для вашего кода пространство имен с файловой областью. Пространство имен с файловой областью автоматически применяется ко всему вашему файлу, без необходимости делать какие-либо отступы.

Другими словами, вы можете пойти от этого:

[pastacode lang=»c» manual=»namespace%20LoggingTestApp%0A%7B%0A%20%20%20%20public%20class%20Startup%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20…%0A%20%20%20%20%7D%0A%7D» message=»» highlight=»» provider=»manual»/]

К этому:

[pastacode lang=»c» manual=»namespace%20LoggingTestApp%3B%0A%0Apublic%20class%20Startup%0A%7B%0A%20%20%20%20…%0A%7D» message=»» highlight=»» provider=»manual»/]

Если вы добавляете блок пространства имен в файл, который использует пространство имен файловой области, он создает вложенное пространство имен, как и следовало ожидать:

[pastacode lang=»c» manual=»namespace%20Company.Product%3B%2F%2F%D0%AD%D1%82%D0%B0%20%D1%81%D1%82%D1%80%D0%BE%D1%87%D0%BA%D0%B0%20%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D0%B5%D1%82%20%D0%BF%D1%80%D0%BE%D1%81%D1%82%D1%80%D0%B0%D0%BD%D1%81%D1%82%D0%B2%D0%BE%20%D0%B8%D0%BC%D0%B5%D0%BD%20Company.Product.Component%0Anamespace%20Component%0A%7B%0A%7D» message=»» highlight=»» provider=»manual»/]

Разработчики C # описывают это изменение как очистку горизонтальных отступов (как глобальное использование должно удалять вертикальные отступы). Общая цель — более короткое, более узкое и лаконичное выражение кода. Но эти изменения также являются частью продолжающейся работы, чтобы сделать C # менее устрашающим для новичков. Объедините глобальное использование и пространства имен с файловой областью, и вы сможете создать консольное приложение Hello World всего за несколько строк, что будет более простым началом, если вы только начали изучать язык.

3. Проверка нулевого параметра

В том же духе сокращения шаблонов, C # имеет очень приятную новую функцию, называемую проверкой нулевых параметров (null parametr checking). Несомненно, вы написали метод, который раньше должен был отклонять нулевые значения. Вероятно, вы использовали код, который выглядел так:

[pastacode lang=»c» manual=»public%20UpdateAddress(int%20personId%2C%20Address%20newAddress)%0A%7B%0A%20%20%20%20if%20(newAddress%20%3D%3D%20null)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20throw%20new%20ArgumentNullException(%22newAddress%22)%3B%0A%20%20%20%20%7D%20%20%20%20…%0A%7D» message=»» highlight=»» provider=»manual»/]

Теперь вы можете попросить C # автоматически вставить эту нулевую проверку, добавив !! в конец имени вашего параметра. В данном случае это newAddress:

[pastacode lang=»c» manual=»public%20UpdateAddress(int%20personId%2C%20Address%20newAddress!!)%0A%7B%0A%20%20%20%20…%0A%7D» message=»» highlight=»» provider=»manual»/]

Теперь, если вы передадите нулевое значение вместо объекта Address, исключение ArgumentNullException будет сгенерировано автоматически.

Подобные детали могут показаться тривиальными, но на самом деле это очень ценный низко висящий плод оптимизации языка. Крупные исследования, изучающие причины катастрофических сбоев программирования, показывают, что одни и те же ошибки, которых легко избежать, повторяются снова и снова, не потому, что концепции в коде слишком сложны, а потому, что чтение кода утомительно, а у людей ограниченная продолжительность концентрации внимания. Уменьшение длины кода сокращает время, необходимое для его просмотра, когнитивную нагрузку, необходимую для его обработки, и вероятность того, что вы пропустите реальную ошибку, потому что ваше внимание притупилось.

4. Обязательные свойства

Раньше вы полагались только на конструкторы классов, чтобы убедиться, что объекты созданы в правильном состоянии. Сегодня мы часто работаем с более легкими конструкциями, такими как автоматически реализованные свойства в этой записи:

[pastacode lang=»c» manual=»public%20record%20Employee%0A%7B%0A%20%20%20%20public%20string%20Name%20%7B%20get%3B%20init%3B%20%7D%0A%20%20%20%20public%20decimal%20YearlySalary%20%7B%20get%3B%20init%3B%20%7D%0A%20%20%20%20public%20DateTime%20HiredDate%7B%20get%3B%20init%3B%20%7D%0A%7D» message=»» highlight=»» provider=»manual»/]

И когда мы создаем экземпляры этих легких объектов, нам нравится делать это быстро с помощью синтаксиса инициализатора объекта:

[pastacode lang=»c» manual=»var%20theNewGuy%20%3D%20new%20Employee%0A%7B%0A%20%20%20%20Name%20%3D%20%22Dave%20Bowman%22%2C%0A%20%20%20%20YearlySalary%20%3D%20100000m%2C%0A%20%20%20%20HiredDate%20%3D%20DateTime.Now()%0A%7D%3B» message=»» highlight=»» provider=»manual»/]

Но что, если ваш объект не имеет смысла, если не заданы определенные свойства? Вы можете добавить конструктор, как обычно, но вам нужно будет заплатить за эту формализацию, добавив еще несколько шаблонов. А копирование значений из параметров в свойства — еще один пример ошибки, которую легко понять, но которую часто делают.

В C# 10 ключевое слово required решает эту проблему:

[pastacode lang=»c» manual=»public%20record%20Employee%0A%7B%0A%20%20%20%20public%20required%20string%20Name%20%7B%20get%3B%20init%3B%20%7D%0A%20%20%20%20public%20decimal%20YearlySalary%20%7B%20get%3B%20init%3B%20%7D%0A%20%20%20%20public%20DateTime%20HiredDate%7B%20get%3B%20init%3B%20%7D%0A%7D» message=»» highlight=»» provider=»manual»/]

Теперь компилятор не позволит вам писать код, который создает Employee, но не устанавливает свойство Name.

5. Ключевое слово field

Команда C # за эти годы много сделала для оптимизации кода с помощью автореализуемых свойств. Показанная выше запись Employee является хорошим примером — она ​​объявляет три неизменяемых свойства с помощью ключевых слов get и init. Данные хранятся в трех частных полях, но эти поля создаются для вас автоматически и управляются без вашего вмешательства. Вы их никогда не увидите.

Автореализованные свойства — это здорово, но на них далеко не уйдешь. Когда они не подходят, вы вынуждены добавить поле поддержки в свой класс и написать обычные методы свойств, как будто вы вернулись в C # версии 2. Но в C# 10 есть новый бэкдор с ключевым словом field, которое предоставляет автоматически созданное резервное поле.

Например, предположим, что вы хотите создать запись, которая немного обрабатывает начальное значение свойства. Вот версия класса Employee, которая гарантирует, что поле HiredDate содержит только информацию о дате из объекта DateTime и не содержит информации о времени:

[pastacode lang=»c» manual=»public%20record%20Employee%0A%7B%0A%20%20%20%20public%20required%20string%20Name%20%7B%20get%3B%20init%3B%20%7D%0A%20%20%20%20public%20decimal%20YearlySalary%20%7B%20get%3B%20init%3B%20%7D%0A%20%20%20%20public%20DateTime%20HiredDate%7B%20get%3B%20init%20%3D%3E%20field%20%3D%20value.Date()%3B%20%7D%0A%7D» message=»» highlight=»» provider=»manual»/]

Этот код очистки красивый, простой и почти декларативный.

Вы можете использовать ключевое слово field для доступа к резервному полю в процедурах get, set или init. Итак, где вам могло понадобиться что-то подобное для проверки свойства в обычном классе:

[pastacode lang=»c» manual=»private%20string%20_firstName%3Bpublic%20string%20FirstName%0A%7B%0A%20%20%20%20get%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20return%20_firstName%3B%0A%20%20%20%20%7D%0A%20%20%20%20set%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20if%20(value.Trim()%20%3D%3D%20%22%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20throw%20new%20ArgumentException(%22No%20blank%20strings%22)%3B%20%20%20%20%20%20%20%20_firstName%20%3D%20value%3B%0A%20%20%20%20%7D%0A%7D» message=»» highlight=»» provider=»manual»/]

Теперь вы можете использовать автоматически реализованные свойство и поле:

[pastacode lang=»c» manual=»public%20string%20FirstName%20%7Bget%3B%0A%20%20%20%20set%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20if%20(value.Trim()%20%3D%3D%20%22%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20throw%20new%20ArgumentException(%22No%20blank%20strings%22)%3B%20%20%20%20%20%20%20%20field%20%3D%20value%3B%0A%20%20%20%20%7D%0A%7D» message=»» highlight=»» provider=»manual»/]

По сути, если вам не нужно изменять тип данных вашего ресурса, больше нет необходимости самостоятельно объявлять вспомогательное поле.

* * *

Конечно, эти 5 подтвержденных функций — далеко не все, что мы увидим в C# 10. Есть еще намеки на то, что мы получим больше работы с выражениями и спорное изменение, которое позволит нам определять статические члены в интерфейсе. Но нам нужно подождать, чтобы увидеть, в чем заключаются эти возможности.

Если вам интересно, как этот список соотносится с потенциальными функциями, о которых мы говорили ранее, история неоднозначна. Пространства имен с файловой областью видимости превратились из страны возможного в официальную территорию C# 10. Здесь нет первичных конструкторов, хотя они частично перекрываются с обязательными полями. А необработанные строковые литералы все еще остаются открытым вопросом. Но общая тема ясна: C# 10 продолжает развиваться, и его внимание сосредоточено на хорошо продуманных удобствах, которые лишь немного облегчают жизнь разработчикам.

Данный текст является переводом статьи Мэтью МакДональда на ресурсе Medium, с оригиналом статьи вы можете ознакомиться по ссылке.