Вышли Превью 6 и 7 .NET 11
Посмотрим на самые интересные новинки в языке C#.
1. Индексаторы-расширения
Члены-расширения теперь включают индексаторы, что позволяет разработчикам добавлять доступ к существующему типу из блока расширения. Т.е. можно добавлять доступ
this[…] к типу из блока расширения. Индексатор-расширение объявляется как индексатор экземпляра внутри блока расширения. В следующем примере добавляется индексация с конца к IReadOnlyList<T>, в котором определён индексатор this[int], но нет индексатора this[Index]:using System;
using System.Collections.Generic;
IReadOnlyList<string> log = ["start", "work", "done"];
Console.WriteLine(log[^1]); // done
Console.WriteLine(log[^2]); // work
public static class ReadOnlyListExtensions
{
extension<T>(IReadOnlyList<T> list)
{
public T this[Index i] =>
list[i.GetOffset(list.Count)];
}
}
2. Метки break и continue
Теперь функции
break и continue могут указывать на окружающий их цикл или оператор switch, поэтому вы можете выйти из внешней конструкции или продолжить её выполнение непосредственно из внутренней, не передавая состояние через флаг и не прибегая к goto. Добавьте метку к целевому циклу, а затем ссылайтесь на него из break или continue:string? found = null;
outer: for (int x = 0; x < xMax; x++)
{
for (int y = 0; y < yMax; y++)
{
if (GetValue(x, y) is { } value && value == target)
{
found = value;
break outer;
}
}
}
Аналогично для
continue:row: for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
if (ShouldSkipRestOfRow(i, j)) continue row;
Process(i, j);
}
}
Метка должна быть прикреплена непосредственно к оператору
for, foreach, while, do или switch, а break/continue с меткой должен находиться внутри этого оператора.3. Шаблоны объединений сопоставляют объединение или его значение
Теперь для типов объединений используется подход сопоставления «попробуй оба варианта»: при применении шаблона к значению объединения компилятор сначала проверяет шаблон на соответствие самому экземпляру объединения, а если эта проверка не удалась, то и на соответствие содержащемуся в объединении значению. Это согласовывает семантику сопоставления с обновлённым спецификатором объединений и применяется к шаблонам типа, переменной, объявления, списка и рекурсивным шаблонам:
public record class Dog(string Name);
public record class Cat(int Lives);
public union Pet(Dog, Cat);
Pet pet = new Cat(9);
// Сопоставление с типом объединения
if (pet is Pet) // true
Console.WriteLine("Это питомец");
// Сопоставление со значением
if (pet is Cat { Lives: > 0 } cat) // true
Console.WriteLine($"У кошки {cat.Lives} жизней");
4. Полнота проверки параметров типа, ограниченных закрытым типом
Полнота проверки параметров с помощью
switch теперь учитывает параметры обобщённых типов, ограниченные закрытым типом. Когда обрабатывается каждый прямой подтип закрытого базового типа, компилятор больше не предупреждает, что оператор switch не является исчерпывающим — даже когда входные данные указываются в качестве параметра типа:public closed record class Shape;
public record class Circle(double Radius) : Shape;
public record class Square(double Side) : Shape;
static double Area<T>(T shape)
where T : Shape => shape switch
{
Circle(var r) => Math.PI * r * r,
Square(var s) => s * s
};
Компилятор решает, что
T не может вводить никаких дополнительных случаев, поскольку каждый производный от Shape тип уже охвачен.Источники:
- https://github.com/dotnet/core/blob/main/release-notes/11.0/preview/preview6/csharp.md
- https://github.com/dotnet/core/blob/main/release-notes/11.0/preview/preview7/csharp.md
