День шестьдесят девятый. #CSharp8
Новые функции в C# 8.
1. Реализация по Умолчанию Интерфейсных Методов
Эта функция помогает вам добавлять функциональность к интерфейсам ваших библиотек, при этом поддерживая обратную совместимость с кодом, написанным для предыдущих версий этих интерфейсов.
Сейчас после того, как вы опубликовали интерфейс, «игра окончена». Вы не можете добавлять члены к интерфейсу без того, чтобы сломать все существующие его реализации.
C# 8.0 позволяет вам предоставить тело члена интерфейса. Поэтому, если кто-то не реализует этот член (возможно, потому что его ещё не существовало на момент написания кода), они просто будут использовать реализацию по умолчанию.
Преимущества
Вы можете добавлять функциональность к интерфейсам, не нарушая совместимость с предыдущими версиями этих интерфейсов.
Недостатки
Это нужно использовать с осторожностью. В противном случае можно легко нарушить принципы единственной ответственности. Подумайте, прежде чем использовать этот инструмент, нет ли другого, более элегантного решения вашей проблемы.
Источник: https://www.c-sharpcorner.com/article/c-sharp-8-features/
Новые функции в C# 8.
1. Реализация по Умолчанию Интерфейсных Методов
Эта функция помогает вам добавлять функциональность к интерфейсам ваших библиотек, при этом поддерживая обратную совместимость с кодом, написанным для предыдущих версий этих интерфейсов.
Сейчас после того, как вы опубликовали интерфейс, «игра окончена». Вы не можете добавлять члены к интерфейсу без того, чтобы сломать все существующие его реализации.
C# 8.0 позволяет вам предоставить тело члена интерфейса. Поэтому, если кто-то не реализует этот член (возможно, потому что его ещё не существовало на момент написания кода), они просто будут использовать реализацию по умолчанию.
interface ILoggerКласс
{
void Log(LogLevel level, string message);
// Новый перегруженный метод
void Log(Exception ex) => Log(LogLevel.Error, ex.ToString());
}
class ConsoleLogger : ILogger
{
public void Log(LogLevel level, string message) { ... }
// Метод Log(Exception) получает реализацию по умолчанию
}
ConsoleLogger
не имеет реализации перегруженного метода Log(Exception)
интерфейса ILogger
, поскольку был объявлен до внесения изменений в интерфейс. Теперь вы можете безопасно добавлять новые члены в существующие публичные интерфейсы, если вы предоставляете реализацию по умолчанию для уже существующих реализаторов.Преимущества
Вы можете добавлять функциональность к интерфейсам, не нарушая совместимость с предыдущими версиями этих интерфейсов.
Недостатки
Это нужно использовать с осторожностью. В противном случае можно легко нарушить принципы единственной ответственности. Подумайте, прежде чем использовать этот инструмент, нет ли другого, более элегантного решения вашей проблемы.
Источник: https://www.c-sharpcorner.com/article/c-sharp-8-features/
👍1
День семьдесят первый. #CSharp8
Новые функции в C# 8.
2. Обнуляемый Ссылочный Тип
В C#8 можно объявлять обнуляемый контекст с помощью аннотации
Для необнуляемых ссылочных типов компилятор использует анализ потока, чтобы убедиться, что локальные переменные инициализированы не-
Обнуляемые ссылочные типы не проверяются на присваивание
Источник: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8
Новые функции в C# 8.
2. Обнуляемый Ссылочный Тип
В C#8 можно объявлять обнуляемый контекст с помощью аннотации
#nullable
. Внутри него любые переменные ссылочного типа считаются необнуляемыми. Если вы хотите присвоить ссылочному типу null
, нужно явно объявить обнуляемый тип переменной с помощью <тип>?
.Для необнуляемых ссылочных типов компилятор использует анализ потока, чтобы убедиться, что локальные переменные инициализированы не-
null
значением. Все поля должны быть инициализированы в конструкторе. Компилятор выдаёт предупреждение, если переменная не объявляется вызовом любого из доступных конструкторов или инициализатором.Обнуляемые ссылочные типы не проверяются на присваивание
null
, однако компилятор использует анализ потока, чтобы убедиться, что переменная обнуляемого типа не содержит null
, прежде чем к ней обращается код или она присваивается переменной необнуляемого типа.Источник: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8
День семьдесят второй. #CSharp8
Новые функции в C# 8.
3. Продвинутое Сопоставление с Шаблоном
Сопоставление выражения с шаблоном предоставляет инструменты для сравнения по форме связанных, но разных типов данных. В C# 7.0 был представлен синтаксис шаблонов типа и шаблонов констант, используя выражения
C# 8.0 расширяет эту функциональность, так что вы можете использовать больше шаблонных выражений в разнообразных местах вашего кода. Используйте эти функции, когда ваши данные и функционал разделены, когда ваши алгоритмы не зависят от типа объекта во время выполнения. В дополнение к новым шаблонам в новых местах, в C# 8.0 вводятся рекурсивные шаблоны. Результат любого шаблона выражения – это выражение. Рекурсивный шаблон – это просто шаблон выражения, применённый к результату другого шаблона выражения.
Преимущества
Рекурсивное сопоставление с шаблоном помогает вам разбить структуры данных на компоненты и использовать их в очень удобном и компактном синтаксисе. Несмотря на то, что сопоставление с шаблоном эквивалентно последовательности выражений if-then, оно помогает вам писать код в стиле функционального программирования.
Недостатки
В сложных выражениях синтаксис может быть хитрым и сложным для понимания.
В следующем примере шаблон выражения используется для сопоставления структуры с шаблоном:
Шаблон свойства позволяет вам сопоставить свойства исследуемого объекта. В следующем примере метод рассчитывает налог с продаж в зависимости от штата (свойство
Некоторые типы включают метод
Источники:
- https://www.c-sharpcorner.com/article/c-sharp-8-features/
- https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8
Новые функции в C# 8.
3. Продвинутое Сопоставление с Шаблоном
Сопоставление выражения с шаблоном предоставляет инструменты для сравнения по форме связанных, но разных типов данных. В C# 7.0 был представлен синтаксис шаблонов типа и шаблонов констант, используя выражения
is
и switch
. C# 8.0 расширяет эту функциональность, так что вы можете использовать больше шаблонных выражений в разнообразных местах вашего кода. Используйте эти функции, когда ваши данные и функционал разделены, когда ваши алгоритмы не зависят от типа объекта во время выполнения. В дополнение к новым шаблонам в новых местах, в C# 8.0 вводятся рекурсивные шаблоны. Результат любого шаблона выражения – это выражение. Рекурсивный шаблон – это просто шаблон выражения, применённый к результату другого шаблона выражения.
Преимущества
Рекурсивное сопоставление с шаблоном помогает вам разбить структуры данных на компоненты и использовать их в очень удобном и компактном синтаксисе. Несмотря на то, что сопоставление с шаблоном эквивалентно последовательности выражений if-then, оно помогает вам писать код в стиле функционального программирования.
Недостатки
В сложных выражениях синтаксис может быть хитрым и сложным для понимания.
В следующем примере шаблон выражения используется для сопоставления структуры с шаблоном:
var point = new 3DPoint(1, 2, 3); //x=1, y=2, z=3Шаблоны свойств
if (point is 3DPoint(1, var myY, _))
{
// Этот код будет выполнен, только если point.X == 1
// myY – это новая переменная,
// которая будет доступна только в этом блоке
// Третий член объекта игнорируется спецсимволом _
}
Шаблон свойства позволяет вам сопоставить свойства исследуемого объекта. В следующем примере метод рассчитывает налог с продаж в зависимости от штата (свойство
State
извлекается из передаваемого объекта типа Address
). Расчёт этого налога не является ответственностью класса Address
, поскольку он может изменяться гораздо чаще, чем структура адреса:public static decimal ComputeSalesTax(Address location, decimal salePrice) =>Позиционные шаблоны
location switch
{
{ State: "WA" } => salePrice * 0.06M,
{ State: "MN" } => salePrice * 0.075M,
{ State: "MI" } => salePrice * 0.05M,
// ...
_ => 0M
};
Некоторые типы включают метод
Deconstruct
, который деконструирует свойства в отдельные переменные. Когда доступен метод Deconstruct
, вы можете использовать позиционные шаблоны для сопоставления свойств с шаблоном. Рассмотрим следующий класс точки с координатами X
и Y
:public class PointТакже у нас имеется перечисление, представляющее собой позицию точки в системе координат: неизвестна, в центре, в первом квадратне, во втором квадранте, …, на оси координат:
{
public int X { get; }
public int Y { get; }
public Point(int x, int y) => (X, Y) = (x, y);
public void Deconstruct(out int x, out int y) =>
(x, y) = (X, Y);
}
public enum QuadrantСледующий метод использует позиционный шаблон для извлечения значений
{
Unknown,
Origin,
One,
Two,
Three,
Four,
OnBorder
}
x
и y
, а также использует условие when
для определения квадранта:static Quadrant GetQuadrant(Point point) => point switchШаблон пустого кортежа
{
(0, 0) => Quadrant.Origin,
var (x, y) when x > 0 && y > 0 => Quadrant.One,
var (x, y) when x < 0 && y > 0 => Quadrant.Two,
var (x, y) when x < 0 && y < 0 => Quadrant.Three,
var (x, y) when x > 0 && y < 0 => Quadrant.Four,
var (_, _) => Quadrant.OnBorder,
_ => Quadrant.Unknown
};
(_, _)
соответствует случаю, когда либо x
, либо y
равно 0, но не оба. Выражение switch
должно либо возвращать значение, либо выбрасывать исключение. Если ни один из вариантов не находит соответствия, выражение switch
выбрасывает исключение. Компилятор выдаст предупреждение, если вы не укажете все возможные варианты в выражении switch
.Источники:
- https://www.c-sharpcorner.com/article/c-sharp-8-features/
- https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8
День семьдесят третий. #CSharp8
Новые функции в C# 8.
4. Асинхронные потоки
Начиная с C# 8.0 вы можете создавать и потреблять потоки асинхронно. Метод, возвращающий асинхронный поток, имеет три свойства:
1. Объявляется с модификатором
2. Возвращает
3. Содержит выражения
Потребитель асинхронного потока должен добавить ключевое слово
Следующий код генерирует последовательность от 0 до 19 с ожиданием 100ms между генерациями каждого числа. Затем можно перебрать последовательность, используя выражение
Заметьте, что для выполнения этого кода требуется установить SDK .NET Core 3.0 и использовать его в качестве Target framework в свойствах проекта. А чтобы он появился в этом списке, возможно, потребуется отметить флажок “Use previews of the .NET Core SDK” в Tools > Options > Projects and Solutions > .NET Core и перезагрузить Visual Studio.
Преимущества
Асинхронные потоки предоставляют замечательную возможность представить асинхронные источники данных, которые могут контролироваться потребителем. Например, при загрузке данных из сети, мы хотели бы создать асинхронную коллекцию, которая возвращает данные по частям, как только те становятся доступными.
Источники:
- https://www.c-sharpcorner.com/article/c-sharp-8-features/
- https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8
Новые функции в C# 8.
4. Асинхронные потоки
Начиная с C# 8.0 вы можете создавать и потреблять потоки асинхронно. Метод, возвращающий асинхронный поток, имеет три свойства:
1. Объявляется с модификатором
async
.2. Возвращает
IAsyncEnumerable<T>
.3. Содержит выражения
yield return
, чтобы возвращать последующие элементы из асинхронного потока.Потребитель асинхронного потока должен добавить ключевое слово
await
перед ключевым словом foreach
при переборе элементов потока. Добавление ключевого слова await
требует, чтобы метод, который перечисляет элементы асинхронного потока, был объявлен с модификатором async
и возвращал тип, разрешенный для асинхронного метода. Обычно это означает возврат типа Task
или Task<TResult>
, а также может быть ValueTask
или ValueTask<TResult>
. Метод может как потреблять, так и производить асинхронный поток, что значит, что он будет возвращать IAsyncEnumerable<T>
. Следующий код генерирует последовательность от 0 до 19 с ожиданием 100ms между генерациями каждого числа. Затем можно перебрать последовательность, используя выражение
await foreach
:using System;
using System.Threading.Tasks;
using System.Collections.Generic;
static async Task Main(string[] args)
{
await foreach (var number in GenerateSequence())
{
Console.WriteLine(number);
}
}
public static async System.Collections.Generic.IAsyncEnumerable<int> GenerateSequence()
{
for (int i = 0; i < 20; i++)
{
await Task.Delay(100);
yield return i;
}
}
Заметьте, что для выполнения этого кода требуется установить SDK .NET Core 3.0 и использовать его в качестве Target framework в свойствах проекта. А чтобы он появился в этом списке, возможно, потребуется отметить флажок “Use previews of the .NET Core SDK” в Tools > Options > Projects and Solutions > .NET Core и перезагрузить Visual Studio.
Преимущества
Асинхронные потоки предоставляют замечательную возможность представить асинхронные источники данных, которые могут контролироваться потребителем. Например, при загрузке данных из сети, мы хотели бы создать асинхронную коллекцию, которая возвращает данные по частям, как только те становятся доступными.
Источники:
- https://www.c-sharpcorner.com/article/c-sharp-8-features/
- https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8
День семьдесят четвёртый. #CSharp8
Новые функции в C# 8.
5. Индексы и диапазоны
Диапазоны и индексы предоставляют краткий синтаксис указания поддиапазонов элементов массива или типов
Вы можете указать индекс с конца, используя оператор
Вы можете указать диапазон с помощью оператора
Рассмотрим следующий массив строк, обозначенный индексами с начала и с конца:
Вы можете получить последнее слово с помощью индекса
Заметьте, что для использования диапазонов требуется установить SDK .NET Core 3.0 и использовать его в качестве Target framework в свойствах проекта. А чтобы он появился в этом списке, возможно, потребуется отметить флажок “Use previews of the .NET Core SDK” в Tools > Options > Projects and Solutions > .NET Core и перезагрузить Visual Studio.
Источник: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8
Новые функции в C# 8.
5. Индексы и диапазоны
Диапазоны и индексы предоставляют краткий синтаксис указания поддиапазонов элементов массива или типов
Span<T>
или ReadOnlySpan<T>
.Вы можете указать индекс с конца, используя оператор
^
. Выражение array[2]
означает "2й элемент с начала". Теперь можно использовать array[^2]
, что означает "2й элемент с конца". Индекс ^0 означает "конец", то есть индекс, следующий за последним элементом.Вы можете указать диапазон с помощью оператора
..
. Например, 0..^0
обозначает весь диапазон массива: 0
с начала до, но не включая, 0
с конца. Любой из операндов оператора может быть как индексом "с начала", так и "с конца". Более того, любой из операндов может быть опущен. По умолчанию 0
– начальный индекс, ^0
– конечный индекс.Рассмотрим следующий массив строк, обозначенный индексами с начала и с конца:
var words = new string[]Индекс каждого элемента усиливает концепцию "с начала" и "с конца", а диапазоны исключают конец диапазона. "Старт" массива – это первый элемент, а "конец" массива находится за последним элементом.
{
// с начала с конца
"The", // 0 ^9
"quick", // 1 ^8
"brown", // 2 ^7
"fox", // 3 ^6
"jumped", // 4 ^5
"over", // 5 ^4
"the", // 6 ^3
"lazy", // 7 ^2
"dog" // 8 ^1
};
Вы можете получить последнее слово с помощью индекса
^1
:Console.WriteLine($"The last word is {words[^1]}");Следующий код создаёт поддиапазон со словами "quick", "brown" и "fox". Он включает элементы с
// выведет "dog"
words[1]
до words[3]
. Элемент words[4]
не входит в диапазон.var quickBrownFox = words[1..4];Следующий код создаёт поддиапазон со словами "lazy" и "dog". Он включает элементы
words[^2]
и words[^1]
. Конечный индекс words[^0]
не включается:var lazyDog = words[^2..^0];Следующие примеры создают диапазоны, открытые с начала, с конца и с обоих концов:
var allWords = words[..]; // содержит все словаВы также можете объявлять диапазоны как переменные, которые потом могут использоваться внутри квадратных скобок:
var firstPhrase = words[..4]; // слова от "The" до "fox"
var lastPhrase = words[6..]; // слова "the", "lazy" и "dog"
Range phrase = 1..4;Заметьте, что, если вы укажете неверный диапазон, где начальное значение больше конечного, то будет выброшено исключение времени выполнения
var text = words[phrase];
System.OverflowException
, например:var invalidRange = words[5..2];При этом компилятор не выдаёт ошибок или предупреждений во время компиляции, даже если вы явно указываете большее начальное значение (по крайней мере в нынешней версии).
var invalidEnd = words[6..^4];
Заметьте, что для использования диапазонов требуется установить SDK .NET Core 3.0 и использовать его в качестве Target framework в свойствах проекта. А чтобы он появился в этом списке, возможно, потребуется отметить флажок “Use previews of the .NET Core SDK” в Tools > Options > Projects and Solutions > .NET Core и перезагрузить Visual Studio.
Источник: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8
День семьдесят пятый. #CSharp8
Новые функции в C# 8.
6. Декларации using
Декларация
Источник: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8
Новые функции в C# 8.
6. Декларации using
Декларация
using
– это определение переменной, которому предшествует ключевое слово using
. Оно сообщает компилятору, что определяемая переменная должна быть высвобождена в конце текущего блока кода: static void WriteLinesToFile(IEnumerable<string> lines)В предыдущем примере переменная file освобождается перед тем, как в коде встречается закрывающая скобка метода. Это конец блока, в котором она определена. Предыдущий пример аналогичен использованию блока using:
{
using var file = new System.IO.StreamWriter("WriteLines2.txt");
foreach (string line in lines)
{
file.WriteLine(line);
}
// переменная file высвобождается здесь
}
using (var file = new System.IO.StreamWriter("WriteLines2.txt"))В обоих случаях компилятор вызывает метод
{
// …
}
Dispose()
. Компилятор выбросит ошибку, если выражение в операторе using
не является освобождаемым.Источник: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8
День семьдесят шестой. #CSharp8
Новые функции в C# 8.
7. Статические локальные функции
Вы теперь можете добавлять модификатор
Рассмотрим следующий код. Локальная функция
Новые функции в C# 8.
7. Статические локальные функции
Вы теперь можете добавлять модификатор
static
к локальным функциям, чтобы убедиться, что локальная функция не включает (не ссылается) на переменные из обрамляющего её блока кода. Если это произойдёт, будет выброшено исключение CS8421 "A static local function can't contain a reference to <variable>." ("Статическая локальная функция не может ссылаться на <имя переменной>.")
.Рассмотрим следующий код. Локальная функция
LocalFunction
ссылается на переменную y
, объявленную в обрамляющем её коде (методе M
). Поэтому LocalFunction
не может быть объявлена статической:int M()Следующий код содержит статическую локальную функцию. Она может быть объявлена статической, поскольку она не содержит никаких ссылок на переменные из обрамляющего её кода:
{
int y;
LocalFunction();
return y;
void LocalFunction() => y = 0;
}
int M()Источник: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8
{
int y = 5;
int x = 7;
return Add(x, y);
static int Add(int left, int right) => left + right;
}