Закрытые иерархии классов в C# 15: ключевое слово closed в .NET 11 Preview 5
C# 15 добавляет модификатор closed в .NET 11 Preview 5, давая иерархиям классов проверку полноты во время компиляции в выражениях switch. Как это работает и единственный подводный камень.
.NET 11 Preview 5 вышел 9 июня 2026 года, и внутри языковой работы C# 15 притаилась возможность, которая тихо устраняет один из старейших пробелов системы типов: не было способа сказать компилятору “у этого базового класса ровно эти подтипы”. Теперь он есть. Новый модификатор closed объявляет закрытую иерархию классов, и выражения switch над ней получают полную проверку полноты во время компиляции.
Это дополнение к объединениям типов. Объединения составляют несвязанные типы; закрытые иерархии запирают дерево наследования, которым вы уже владеете. Вместе они дают C# полную историю исчерпывающей проверки.
Что на самом деле делает closed
Пометьте базовый класс как closed, и компилятор разрешит только прямые подтипы, которые находятся в той же сборке. Поскольку множество подтипов теперь известно и конечно, компилятор может проверить, что switch обрабатывает каждый достижимый случай.
public closed record class GateState;
public record class Closed : GateState;
public record class Open(float Percent) : GateState;
static string Describe(GateState state) => state switch
{
Closed => "closed",
Open(var percent) => $"{percent}% open"
};
Без ветви default, без шаблона отбрасывания, без throw new InvalidOperationException("unreachable"). Компилятор уже знает, что Closed и Open — единственные варианты. Добавьте позже третий подтип, и каждый неисчерпывающий switch загорится предупреждением, и это именно та страховочная сеть для рефакторинга, которой паттерны из запечатанного класса плюс посетитель никогда не давали.
Правила, которые кусают
Несколько ограничений стоит запомнить:
- Класс
closedявляется неявно абстрактным. Нельзя создать экземпляр базы напрямую и нельзя сочетатьclosedсsealed,staticили явным модификаторомabstract. - Прямые подтипы должны быть объявлены в той же сборке. Наследование между сборками заблокировано, и именно это делает закрытое множество познаваемым.
- Это применимо к классам и
record class, но не к структурам.
Единственный подводный камень в Preview 5
Вот часть, на которой вы споткнётесь. Компилятор выпускает маркер System.Runtime.CompilerServices.ClosedAttribute, но среда выполнения в Preview 5 этот атрибут пока не поставляет. Пока этого не произойдёт, каждый проект, использующий closed, должен объявить атрибут сам:
namespace System.Runtime.CompilerServices;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public sealed class ClosedAttribute : Attribute { }
Поместите это в любой файл проекта, и возможность скомпилируется. Ожидайте, что он исчезнет в более поздней preview, как только BCL принесёт этот тип. Это обычный налог previews, поэтому не вшивайте заглушку в общую библиотеку, которую планируете публиковать.
Закрытые иерархии, закрытые перечисления и объединения типов сегодня в C# 15 все находятся за <LangVersion>preview</LangVersion> и движутся к общей доступности с .NET 11 в ноябре 2026 года. Если вы когда-либо писали switch с недостижимым default только ради того, чтобы удовлетворить компилятор, это та возможность, которая наконец его удаляет. Все подробности в примечаниях к выпуску C# для Preview 5.
Comments
Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.