Technology

C# 15 Biggest Changes: Union Types, Closed Hierarchies, Memory Safety & More

C# 15 is the next major language release in the .NET ecosystem — and for teams building enterprise applications, APIs, and SaaS products on ASP.NET Core, it is worth understanding early. At NovIqra we ship production software on .NET every day, so we follow these language changes closely: they shape how we model domain logic, write safer code, and plan upgrades for client platforms.

This article explains when C# 15 releases, its biggest changes, and the practical advantages for developers and architects — based on Microsoft's official documentation and the current .NET 11 preview SDKs available in mid-2026.

C# 15 release date and availability

C# 15 is scheduled for general availability in November 2026, alongside the release of .NET 11. Microsoft ships C# language features with the corresponding .NET SDK — C# 15 requires the .NET 11 SDK and is not available as a standalone compiler drop for older runtimes.

As of July 2026, the timeline looks like this:

  • Now (preview): C# 15 features are available through .NET 11 preview SDKs and Visual Studio 2026 Insiders builds. You can download previews from the official .NET downloads page and experiment today.
  • November 2026 (GA): C# 15 and .NET 11 reach general availability as a Standard Term Support (STS) release.
  • Language versioning: Set <LangVersion>15</LangVersion> (or preview for the earliest memory-safety relaxations) in your project file once you target net11.0.

Important for production planning: .NET 10 is the current Long Term Support (LTS) release (supported through November 2028). .NET 11 is STS — ideal for teams that want the newest language and runtime features, but many enterprises will stay on .NET 10 LTS for stability while evaluating C# 15 in parallel branches or greenfield services.

Overview: the four headline features in C# 15

Microsoft groups the C# 15 release around four major themes:

  • Union types — values that can be one of several defined case types, with compile-time exhaustiveness checking
  • Closed hierarchies — classes whose direct descendants are fixed to the declaring assembly
  • Collection expression arguments — pass constructor or factory parameters inside [...] collection expressions
  • Memory safety — a multi-release effort to separate pointer declaration from unsafe memory access

Union types and closed hierarchies are the biggest day-to-day modeling changes. Collection expression arguments refine syntax developers already use from C# 12. Memory safety is foundational — the full model rolls out across multiple previews and releases.

1. Union types — discriminated unions, built into the language

Perhaps the most talked-about addition in C# 15 is union types. A union represents a value that can be exactly one of several case types — similar to discriminated unions in F#, Rust enums with payloads, or Kotlin sealed-interface patterns, but now as first-class C# syntax.

Declare a union with the union keyword:

public record class Cat(string Name);
public record class Dog(string Name);
public record class Bird(string Name);

public union Pet(Cat, Dog, Bird);

Each case type converts implicitly to the union, and switch expressions must handle every case:

Pet pet = new Dog("Rex");

string name = pet switch
{
    Dog d => d.Name,
    Cat c => c.Name,
    Bird b => b.Name,
};

Why union types matter

  • Replace stringly-typed results — API responses like "success" | "notFound" | "error" become typed cases instead of magic strings and integer codes.
  • Compiler-checked exhaustiveness — if you add a new case to the union, every switch that handles it must be updated or the compiler warns. Fewer runtime surprises.
  • Cleaner than inheritance for closed sets — when a value is one of a fixed set of shapes, unions express intent more directly than abstract base classes.
  • Better domain modeling — payment outcomes, validation results, workflow states, and external API responses map naturally to union cases.

Runtime support: UnionAttribute and IUnion ship in .NET 11 Preview 5 onward. Some advanced features from the full specification — such as union member providers — are still arriving in later previews, so check the Roslyn feature status page if you adopt early.

2. Closed hierarchies — fixed inheritance trees the compiler understands

C# has long used abstract base classes and interfaces for polymorphism, but the compiler rarely knows the complete set of descendants — especially across assemblies. C# 15 introduces the closed modifier to fix that for classes defined in your assembly.

public closed record class GateState;
public record class Closed : GateState;
public record class Open(float Percent) : GateState;

string Describe(GateState state) => state switch
{
    Closed => "closed",
    Open(var percent) => $"{percent}% open",
    // Exhaustive — no default arm required.
};

Rules and behaviour

  • A closed class can only be derived within its declaring assembly. External assemblies cannot add new subclasses.
  • Closed classes are implicitly abstract — you cannot combine closed with sealed, static, or an explicit abstract modifier.
  • Derivation is not transitive — a non-closed child of a closed class can still be extended from other assemblies unless you also mark it closed.
  • The compiler treats switch over a closed hierarchy as exhaustive when all direct descendants are handled — no _ default needed.

Advantages of closed hierarchies

  • Safer refactoring — adding a new state to a closed domain model forces compile-time updates everywhere it is consumed.
  • Less defensive coding — fewer default => throw new UnreachableException() arms in switches.
  • API design clarity — library authors can publish a fixed set of extension points without worrying about uncontrolled subclassing in consumer code.

Preview note: as of C# 15 Preview 5, System.Runtime.CompilerServices.ClosedAttribute is not yet in the runtime. Projects using closed must declare the attribute locally until the final .NET 11 runtime ships — Microsoft documents the workaround in the official C# 15 release notes.

3. Collection expression arguments — more control inside [...] syntax

C# 12 introduced collection expressions — concise [item1, item2, ...] syntax for arrays, spans, lists, and other collection types. C# 15 extends that with collection expression arguments, letting you pass parameters to the underlying constructor or factory using a with(...) element as the first entry.

string[] values = ["one", "two", "three"];

// Pass capacity to List<T> constructor
List<string> names = [with(capacity: values.Length * 2), .. values];

// Pass comparer to HashSet<T>
HashSet<string> set = [
    with(StringComparer.OrdinalIgnoreCase),
    "Hello", "HELLO", "hello"
];
// Set contains one element — OrdinalIgnoreCase treats them as equal.

Advantages

  • Less ceremony — no need to split collection creation across a new List<T>(capacity) line and a separate populate step.
  • Performance hints stay local — pre-sizing collections with the right capacity reduces reallocations in hot paths.
  • Comparer and options inlineHashSet, Dictionary, and similar types accept comparers or capacity right in the expression.
  • Consistent style — teams already adopting collection expressions get more expressive power without switching syntax.

4. Memory safety — separating pointers from dangerous operations

C# 15 begins a multi-release memory safety initiative. Today, marking code unsafe is coarse-grained: declaring a pointer type, taking an address, or using fixed all live inside an unsafe context — even when no memory is actually dereferenced.

The long-term goal:

  • Unsafe context tied to memory access — operations that read or write through pointers (dereference, p->member, p[i], function pointer calls) require unsafe.
  • Pointer declaration relaxed — with the preview language version, declaring pointer types, taking & addresses, using fixed, stackalloc-to-pointer conversions, and sizeof on unmanaged types no longer require an unsafe block.
  • Requires-unsafe members (coming in a later preview) — methods that perform unsafe operations mark callers, and assemblies can opt in via MemorySafetyRulesAttribute.
  • safe keyword (coming later) — explicitly mark extern members and explicit-layout fields as safe boundaries.
int number = 42;
int* pointer = &number;

int[] numbers = [10, 20, 30];
fixed (int* first = numbers)
{
    // Dereferencing *first still requires unsafe { }.
}

Advantages for security and code review

  • Auditors see real risk — unsafe blocks highlight actual memory access, not boilerplate pointer setup.
  • Gradual tightening — teams with interop, game engines, or high-performance components can adopt rules incrementally.
  • Aligns with industry direction — languages and runtimes are moving toward provable memory safety; C# is modernizing without abandoning unmanaged interop.

Practical advantages of upgrading to C# 15

Beyond individual features, C# 15 delivers broader benefits for .NET teams:

Stronger compile-time guarantees

Union types and closed hierarchies push errors left — from production runtime failures to compile-time warnings. For enterprise systems with large codebases and many contributors, that shift reduces defect rates and review burden.

More expressive domain models

Result types, state machines, event payloads, and integration responses become easier to model without third-party discriminated-union libraries or verbose class hierarchies. Less glue code means faster delivery and clearer onboarding for new developers.

Better alignment with modern C# style

Collection expressions, records, pattern matching, and now unions and closed types form a coherent story: immutable data, expression-oriented code, and compiler-verified completeness. Teams standardizing on this style write less imperative branching and fewer null checks.

Foundation for safer low-level code

The memory safety work benefits any team using pointers for P/Invoke, networking buffers, or performance -critical paths — without giving up C#'s managed-runtime advantages for the majority of application code.

What to watch before adopting in production

  • Preview completeness — union member providers, full memory-safety enforcement, and runtime attributes like ClosedAttribute are still landing across previews. Treat early adoption as evaluation, not production default until GA.
  • .NET 11 is STS, not LTS — if your organization requires long support windows, plan C# 15 experiments on .NET 11 while keeping LTS services on .NET 10 until policy allows STS upgrades.
  • Breaking changes — Microsoft publishes a C# / .NET 11 compiler breaking changes document. Run preview builds in CI before flipping language version globally.
  • Tooling — IDE support for union types improved through 2026 previews (refactoring, navigation). Ensure your team uses a compatible Visual Studio or VS Code + C# Dev Kit version.

How we see C# 15 at NovIqra

We build client platforms and products — including NoviMeet and NoviManager — on ASP.NET Core and modern C#. C# 15's union types and closed hierarchies are especially relevant for API contracts, workflow states, and validation pipelines where "one of several outcomes" appears constantly. Collection expression arguments are a quality-of-life win in data-heavy services. Memory safety matters for any team shipping interop or performance-sensitive components alongside standard web APIs.

Our recommendation: start experimenting in .NET 11 preview branches now, identify where union types replace brittle enums or string codes in your domain, and plan a staged upgrade path aligned with your LTS/STS policy — so you are ready when C# 15 goes GA in November 2026.

Summary

  • Release: C# 15 GA with .NET 11 in November 2026; available in preview SDKs today.
  • Biggest changes: union types, closed hierarchies, collection expression arguments, memory safety (phase 1).
  • Top advantages: compile-time exhaustiveness, clearer domain modeling, safer memory boundaries, and more expressive collection syntax.
  • Action: download .NET 11 preview, enable C# 15 in a test project, and map one real domain concept to a union type — you will feel the difference immediately.

← Back to all posts