В C# 15 появились break и continue с меткой в .NET 11 Preview 7
break и continue с меткой попали в раздел C# в .NET 11 Preview 7. Теперь метку можно поставить прямо на цикл и перейти к нему напрямую, что отправляет на покой обходные приёмы с булевым флагом и goto во вложенных циклах.
.NET 11 Preview 7 вышел 2026-08-11, и в разделе C# оказалась возможность, которую сообщество просило чуть ли не всегда: break и continue теперь могут указывать метку охватывающего цикла или switch. Курируемое предложение это dotnet/csharplang#9875, а приложенный к нему список обсуждений ссылается на девять отдельных тем сообщества, которые тянутся годами.
Как выглядит синтаксис
Метка ставится непосредственно на цикл, а инструкция перехода её называет:
outer: for (int row = 0; row < grid.Height; row++)
{
for (int column = 0; column < grid.Width; column++)
{
if (grid[row, column].IsBlocked)
{
continue outer;
}
if (grid[row, column].IsGoal)
{
break outer;
}
}
}
Одной метки хватает для обоих переходов. Без метки break и continue ведут себя ровно как раньше и нацелены на ближайшую подходящую внутреннюю инструкцию, так что изменение чисто дополняющее.
Два обходных приёма, которые это заменяет
Вариант с булевым флагом требует состояния, которое существует лишь для того, чтобы протолкнуть выход наружу, и проверять его приходится на каждом уровне:
bool found = false;
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (i * j > 20)
{
found = true;
break;
}
}
if (found)
break;
}
Вариант с goto для случая continue ещё хуже, потому что метку нужно разместить в конце тела цикла, чтобы инкремент и проверка условия всё же выполнились:
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (j == 5)
goto next;
}
next: ; // The empty statement is required.
}
Это хрупко. Любая инструкция, случайно вставленная между меткой и закрывающей скобкой, незаметно меняет смысл перехода. Привязка метки к самой конструкции цикла убирает такой сценарий отказа.
Два правила, которые стоит знать до рефакторинга
Метку получает только та инструкция, которая вложена непосредственно внутрь помеченной инструкции. В случае a: b: while (...) ... цикл помечает лишь b. a помечает внутреннюю помеченную инструкцию, а она сама циклом не является, поэтому break a; внутри этого тела даёт ошибку компиляции вместо перехода к while. Спецификация явно отвергает вложенные метки.
Кроме того, break может нацеливаться на охватывающий switch, а continue нет. continue всегда разрешается в инструкцию итерации, что следует из смысла каждого из двух переходов.
Анализатор, который найдёт ваши существующие случаи
Искать подходящий код вручную не нужно. IDE0410 (“Use labeled jump statement”) отмечает все три шаблона: goto, перепрыгивающий за вложенный цикл, goto на пустую метку в конце и цепочку проталкивания через булев флаг. Правило включено по умолчанию через csharp_style_prefer_labeled_jump_statements = true и применяется начиная с C# 15. Отключить его для проекта можно так:
[*.cs]
dotnet_diagnostic.IDE0410.severity = none
Чтобы попробовать, нужна предварительная версия SDK .NET 11, как и в случае с индексаторами расширений из Preview 6. Полные подробности есть в спецификации возможности и в анонсе Preview 7.
Comments
Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.