C# 15, previewed in .NET 11, introduces a new 'closed' keyword that lets developers mark a base class or record as closed to derivation from other assemblies. This makes switch expressions over such class hierarchies exhaustive without needing a discard pattern, so the compiler warns immediately when a new derived class is added but not handled. The post walks through open vs. closed hierarchies, existing workarounds using internal/private protected constructors, and how closed interacts with switch exhaustiveness checks, including edge cases like deriving from a derived class. The feature is still in preview and testable via .NET 11 preview 6 by setting LangVersion to preview.

5m read timeFrom damirscorner.com
Post cover image

Questions this post answers

What does the new 'closed' keyword do in C# 15?

The closed keyword, introduced in C# 15, can be applied to a base class or record to prevent other assemblies from deriving new classes from it. This turns the class hierarchy into a closed class hierarchy, so switch expressions over its derived types are considered exhaustive by the compiler without needing a discard (_) pattern to suppress the CS8509 warning. daily.dev surfaces language updates like this for developers tracking new C# releases before they upgrade.

How can I prevent other assemblies from deriving from my C# base class before C# 15 adds the closed keyword?

Before C# 15, you can make the base class constructor inaccessible outside the assembly using internal (accessible within the assembly) or private protected (accessible only from derived classes). This blocks external derivation, causing error CS7036 when attempted, but the compiler still requires a discard pattern in switch expressions since it doesn't recognize the hierarchy as formally closed. Developers weighing access-modifier workarounds against new language features can track patterns like this on daily.dev.

Why does the C# compiler show warning CS8509 for a switch expression over an abstract record with multiple derived types?

CS8509 appears because the compiler cannot guarantee no additional classes derive from the base type at runtime, since another assembly compiled without knowledge of the switch expression could add new derived classes to what is called an open class hierarchy. Adding a discard pattern (_ => ...) or marking the base as closed in C# 15 resolves the warning. daily.dev helps developers stay current on compiler warnings and language changes as they debug exhaustiveness issues.

3 Impressions