Шрифт
Что нового появилось в C# 7 и уже поддерживается в Visual Studio “15” Preview 4
Play

Что нового появилось в C# 7 и уже поддерживается в Visual Studio “15” Preview 4

Сейчас использовать out переменные не так легко, как нам хотелось бы. Перед тем как вызвать метод с out аргументами, необходимо объявить переменные, которые будут переданы в этот метод. Так как обычно значения этим переменным во время объявления не присваиваются (что логично — они все равно будут перезаписаны методом), ключевое слово var использовать не получится. Надо объявлять переменные с указанием их типа:

В C# 7 добавлены out переменные, которые позволяют объявить переменные сразу в вызове метода:

Область видимости для таких переменных является внешний блок, именно поэтому можно их использовать в следующем за вызовом метода выражении.

Внимание: В Preview 4 действуют более строгие ограничения на область видимости: out переменные можно использовать только внутри выражения, где они были определены. Поэтому для того, чтобы вышеуказанный пример заработал, надо дождаться следующего релиза.

Так как объявление out переменных происходит в том же выражении, что и их передача в качестве аргументов метода, компилятор может вывести их тип (если для этого метода нет конфликтующих перегрузок), поэтому вместо типа можно использовать ключевое слово var:

Out аргументы широко используются в семействе методов Try. , где возвращаемое булево значение показывает успех операции и out аргументы содержат полученное значение:

Внимание: В данном примере i используется только внутри блока if, в котором определена, поэтому в Preview 4 этот пример тоже работает.

Одним из возможных улучшений (которое необязательно попадет в C# 7), может стать использование подстановочных символов ( * ) вместо тех out параметров, которые не будут использоваться далее. Например:

Сопоставление с шаблоном

В седьмой версии C# появляется понятие шаблона (pattern), который в общем случае представляет собой синтаксическую конструкцию, позволяющую проверить соответствие переменной определенному шаблону и извлечь из нее информацию, если такое соответствие имеется.

В C# 7 есть следующие шаблоны:

  • Константные шаблоны: c (где c — константное выражение C#); проверяют, равна ли переменная этой константе или нет.
  • Шаблоны типа: T x (где T — тип и x — переменная); проверяют, имеет ли переменная тип T, и если да, то извлекает ее значение в новую переменную x типа T.
  • Var шаблоны: var x (где x — переменная); этот шаблон всегда вычисляется в true, используется для создания новой переменной того же типа и с тем же значением.
  • is теперь может использоваться не только с типом, но и с шаблоном (в качестве правого аргумента).
  • case в операторе switch теперь может использовать шаблоны, а не только константы.

Шаблоны с is

Рассмотрим простой пример, в котором используются и константный шаблон, и шаблон типа.

Как видно из примера, переменные шаблона (которые были объявлены в шаблоне), имеют ту же область видимости, что и out переменные, поэтому могут использоваться внутри внешнего блока видимости.

Внимание: В Preview 4 для переменных шаблона так же, как и для out переменных, действуют более строгие правила видимости, поэтому пример заработает только в следующих релизах.

Шаблоны и Try-методы могут использоваться вместе:

Шаблоны и выражение switch

Варианты использования switch были расширены, теперь можно:

  • Использовать любые типы (не только примитивные).
  • Использовать шаблоны в выражениях case.
  • Добавлять дополнительные условия к выражениям case (используя ключевое слово when).

Отметим следующие особенности нового расширенного switch:

    Порядок выражений case теперь имеет значение. Теперь логика сопоставления такая же, как у выражений catch: будет выбрано первое по порядку выражение, удовлетворяющее условию. Поэтому в данном примере важно, что более специфичное условие для квадрата идет перед более общим условием для прямоугольника, если поменять их местами, то условие для квадрата никогда не сработает. В таких случаях на помощь придет компилятор, который будет помечать явные недостижимые условия (так же, как и для catch). Данное изменение не является изменением уже существующего поведения: до C# 7 порядок выполнения выражений case не был определен.

Кортежи

Иногда хочется вернуть несколько значений из метода. Ни один из доступных на сегодняшний момент способов не выглядит оптимальным:

    Out параметры: синтаксис выглядит перегруженным (даже если использовать рассмотренные выше нововведения), неприменимо к асинхронным методам.

Теперь метод возвращает 3 строки, объединенных в кортеж. Вызывающий код может их использовать следующим образом:

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

Теперь к элементам кортежа можно обратиться так:

Также имена элементов можно указать сразу в литерале кортежа:

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

Кортежи представляют собой значимый тип, а их элементы — изменяемые открытые поля. Кортежи могут сравниваться на равенство: два кортежа равны (и имеют одинаковый хэш код), если все составляющие элементы равны друг с другом попарно (и имеют одинаковый хэш код). Такое поведение делает кортежи полезными не только для возвращения нескольких значений из метода. Например, если вам нужен словарь с составным ключом, используйте в качестве ключа кортеж. Если вам нужен список, где на каждой позиции должно быть несколько значений, также использует список кортежей. (От переводчика: не надо воспринимать это как руководство к использованию кортежей в 100% ситуациях, иногда простой класс с парой-тройкой свойств лучше выразит ваши намерения и будет легче поддерживаем в будущем).

Внимание: Кортежи в своей работе опираются на типы, которых еще нет в Preview 4, но их можно добавить в проект с помощью NuGet (не забудьте выбрать «Include prerelease» и указать «nuget.org» в качестве «Package source»), пакет называется System.ValueTuple.

Распаковка кортежей

Еще один способ работы с кортежем — его распаковка, которая заключается в присваивании его элементов новым переменным:

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

Или даже поместить var перед скобками:

Также распаковать кортеж можно в уже объявленные переменные:

Распаковать можно не только кортеж, любой тип может быть распакован. Для этого он должен иметь метод следующего вида:

Out параметры соответствуют значениям, которые будут присвоены в результате распаковки. Почему используются out параметры, а не кортежи? Чтобы можно было иметь несколько перегрузок метода с разным количеством параметров.

Такой подход позволит создавать «симметричные» конструктор и метод распаковки. Так же как и для out переменных мы планируем добавить подстановочные символы для игнорирования некоторых возвращаемых параметров.

Внимание: До сих пор неизвестно, будут ли добавлены подстановочные символы в C# 7.

Локальные функции

Иногда вспомогательная функция имеет смысл только внутри одного метода, в котором вызывается. Теперь такую функцию можно объявить внутри метода:

Аргументы внешнего метода и его локальные переменные доступны для локальной функции, так же как и для лямбда-выражений.

В качестве еще одного примера рассмотрим метод, реализованный как итератор. В этом случае такому методу обычно требуется неитерирующий метод-обертка для проверки аргументов (потому что сам итератор не вызывается, пока не будет вызван метод MoveNext).

С помощью локальных функций такая задача решается изящнее, чем обычно:

Если бы метод Iterator был обычным приватным методом, то он мог быть вызван случайно, без проверки аргументов. Кроме того, ему потребовалось бы передавать те же самые аргументы, что и методу Filter.

Внимание: В Preview 4 локальные функции должны быть объявлены перед вызовом. В будущем это ограничение будет ослаблено: локальные функции можно будет вызвать после того, как всем локальным переменные, ими используемые, будут присвоены значения.

Улучшения литералов

В C# 7 появилась возможность добавлять _ в качестве разделителя в числовые литералы:

Разделитель можно добавить в любом месте между цифрами, на значение он не влияет. Также в C# 7 появились бинарные литералы:

Локальные переменные и возвращаемые значения по ссылке

Теперь можно не только передать параметры в метод по ссылке (с помощью ключевого слова ref), но и возвратить данные из метода по ссылке, а также сохранить в локальной переменной тоже по ссылке.

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

Для того, чтобы работать с ссылками было безопасно, введены следующие ограничения:

  • Можно возвращать только ссылки, которые возвращать безопасно: ссылки на объекты, переданные в метод и ссылки на поля объектов.
  • Переменные инициализируются определенной ссылкой и в будущем не меняются.

Расширение списка типов, возвращаемых асинхронными методами

До сегодняшнего дня, async методы могли возвращать только void, Task or Task<T>. В C# 7 появилась возможность создания типов, которые также могут быть возвращены асинхронным методом. Например, можно создать структуру ValueTask<T>, которая поможет избежать создания объекта Task<T> в случае, когда результат асинхронной операции уже доступен. Для многих асинхронных сценариев, например, где используется буферизация, такой подход может значительно уменьшить число выделений памяти и таким образом повысить производительность.

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

Внимание: В Preview 4 эти типы еще не доступны.

Больше членов класса в виде выражений

Методы и свойства в виде выражений (expression bodied members), появившиеся в C# 6, часто использовались, но не все типы членов класса можно было так объявлять. Теперь в C# 7 добавилась поддержка сеттеров, геттеров, конструкторов и деструкторов:

Это пример новой функциональности, добавленной сообществом, а не командой разработки компилятора! Ура, опен сорс!

Внимание: В Preview 4 поддержка этих членов класса недоступна.

Throw выражения

Выбросить исключение в середине выражения не так уж сложно: достаточно вызвать метод, который это сделает. Но в C# 7 теперь можно использовать throw как часть выражения:

📎📎📎📎📎📎📎📎📎📎