Partial Constructors and Partial Events in C# 14

Mastering Declarative Class Composition for a New Era of Source-Generated C#

C# has supported partial classes for many years – the foundation of code generation in ASP.NET, WinForms, Entity Framework, gRPC, MAUI, Orleans, and countless tools that generate C# code into separate files.

But until C# 14, there was one major limitation:
constructors and events could not be partial.

This meant:

  • Source generators couldn’t contribute constructor logic
  • Frameworks had to emit fragile workarounds
  • DI frameworks had to guess what constructors exist
  • Events with generated add/remove logic couldn’t participate in partial APIs
  • Mixed human-written + generated logic was difficult to achieve cleanly

C# 14 fixes this with the introduction of:

  • Partial Constructors
  • Partial Events

A massive quality-of-life leap for modern tooling, metaprogramming, and declarative class building.


🔍 The Problem: Constructors and Events Were “All or Nothing”

C# allowed this:

public partial class Customer
{
    public string Name { get; set; }
}

But not this:

public partial Customer() { }

or:

public partial event EventHandler Updated;

This meant:

❌ Constructors couldn’t be shared

Generated code could add methods or fields, but not constructor logic.

Frameworks such as:

  • Entity Framework Core
  • Blazor
  • WPF
  • WinForms
  • Orleans
  • Mediator frameworks
  • UI code generators

…all had to rely on fragile hacks like:

  • Factory methods
  • Partial methods pretending to be constructors
  • Code that invokes callbacks manually

❌ Events couldn’t be composed

You could not have:

  • Human-written logic + generated logic in the same event
  • Hooks into event add/remove logic
  • Partial definitions of event wrappers
  • Modular event pipelines across generated files

Partial methods helped, but they were not enough.

C# 14 finally addresses this.


⚡ The Solution: Partial Constructors and Partial Events

C# 14 allows both constructors and events to be declared as partial, enabling distributed definitions across multiple files.


🧠 Conceptual Model: “Composable Class Initialization and Event Pipelines”

Partial Constructors

A constructor may be defined across multiple partial class files:

public partial class User
{
    public partial User(string name);
}

In another file:

public partial class User
{
    public partial User(string name)
    {
        Name = name;
    }
}

The compiler merges them into one constructor, in source order.

This allows:

  • Framework-generated constructor logic
  • Hand-authored constructor code
  • DI-friendly declarative constructor composition
  • Cleaner initialization pipelines

Partial Events

Like partial constructors, partial events can define:

  • An event declaration
  • Additional attached or detached logic
  • Custom accessor logic
  • Generated or manual event wiring

🧩 Real-World Example: Source-Generated Validation in a Constructor

File 1 — human-written constructor

public partial class Customer
{
    public partial Customer(string name)
    {
        Name = name;
    }
}

File 2 — generated validation logic

public partial class Customer
{
    public partial Customer(string name)
    {
        if (string.IsNullOrWhiteSpace(name))
            throw new ArgumentException("Name cannot be empty.");
    }
}

Resulting merged output (conceptually):

public Customer(string name)
{
    if (string.IsNullOrWhiteSpace(name))
        throw new ArgumentException("Name cannot be empty.");

    Name = name;
}

Pure, elegant, and composable.


🧩 Real-World Example: Partial Events in a UI or MVVM Framework

File 1 — Human code:

public partial class Dashboard
{
    public partial event EventHandler Refreshed;
}

File 2 — Generated instrumentation:

public partial class Dashboard
{
    public partial event EventHandler Refreshed
    {
        add
        {
            Console.WriteLine("Handler added");
            _refreshed += value;
        }
        remove
        {
            Console.WriteLine("Handler removed");
            _refreshed -= value;
        }
    }
}

File 3 — Another generator:

public partial class Dashboard
{
    public partial event EventHandler Refreshed
    {
        add
        {
            Telemetry.Track("RefreshHandlerAdded");
        }
        remove
        {
            Telemetry.Track("RefreshHandlerRemoved");
        }
    }
}

This creates a pipeline of add/remove behavior enforced by the compiler.


🔬 Under the Hood: How the Compiler Merges Partial Members

Constructors

The compiler concatenates all partial constructor bodies in:

  • The order they appear
  • Across all partial class files
  • With consistent parameter signatures

Rules:

  • All partial constructor definitions must have identical signatures
  • Only one can omit a body (declaration only)
  • The merged order follows file/compile order (predictable)

Events

Partial events are merged by:

  • Combining event declarations
  • Combining accessor bodies (add/remove)
  • Respecting explicit and implicit backing fields

If accessors exist in multiple files, their bodies are merged sequentially.

This is similar to how partial methods were extended in previous C# versions.


🧱 Advanced Usage: Framework-Level Scenarios

1. Dependency Injection (DI)

A source generator can add DI registration logic inside a constructor:

public partial Customer(IServiceProvider provider);

2. ORMs & Data Mappers

Generators can add:

  • Change tracking hooks
  • Lazy-loading logic
  • Validation
  • Mapping hints

…directly into the constructor body.

3. UI Systems

Event composition becomes trivial:

  • Auto-refresh
  • Telemetry
  • Logging
  • Lifecycle hooks

4. Game Engines

Entity constructors can have:

  • Generated physics initialization
  • Component injection
  • Scripting hooks

5. API Frameworks

Auto-generated events can merge:

  • Observability pipelines
  • Caching layers
  • Request mutation handlers

🧰 Integration Scenarios

Libraries & Frameworks

Clean extension points for metaprogramming.

Enterprise Apps

Class initialization becomes modular and declarative.

Tooling

Source generators gain fine-grained control.

UI & Data-Binding

Fine control over event pipelines.

Education

Demonstrates compiler-driven code composition elegantly.


🧩 Best Practices

✔️ For Partial Constructors

  • Keep human-written logic at the end of the constructor
  • Let generated files handle validation, tracking, and metadata
  • Avoid side effects in generated constructors
  • Keep signatures stable to avoid merge errors

✔️ For Partial Events

  • Use explicit accessor blocks for clarity
  • Define a private backing field where appropriate
  • Be aware that events may now run multiple add/remove sequences

❌ Avoid

  • Deeply nested partial event pipelines
  • Ordering-dependent side effects
  • Mixing conflicting accessors across tools

Summary

ConceptBefore C# 14After C# 14
Partial constructorsNot allowedFully supported
Partial eventsNot allowedFully supported
Source generator flexibilityLimitedMassive increase
Constructor compositionManual, messyDeclarative and merged
Event pipelinesSingle-file onlyMulti-file composable
BoilerplateHighDramatically reduced

Final Thoughts

The arrival of partial constructors and partial events in C# 14 is a major milestone for the ecosystem. They unlock a new era of:

  • Declarative initialization
  • Framework-driven composition
  • Rich tooling without hacks
  • Robust and predictable code generation
  • Reduced boilerplate
  • Better separation between human-written and generated logic

These features will benefit almost every modern C# developer – especially those building or using advanced frameworks and generators.