Start Debugging

Закрытые иерархии классов в 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 загорится предупреждением, и это именно та страховочная сеть для рефакторинга, которой паттерны из запечатанного класса плюс посетитель никогда не давали.

Правила, которые кусают

Несколько ограничений стоит запомнить:

Единственный подводный камень в 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.

< Назад