Skip to content

Generator: Create Bridge Pattern #34

@JerrettDavis

Description

@JerrettDavis

Generator: Create Bridge Pattern

Summary

Add a source generator that produces boilerplate-free, GoF-consistent Bridge pattern scaffolding, separating an abstraction from its implementation with explicit contracts and generated forwarding.

The generator lives in PatternKit.Generators and emits self-contained C# with no runtime PatternKit dependency.

Primary goals:

  • Generate the “abstraction” and “implementor” wiring consistently.
  • Avoid hand-written forwarding drift.
  • Support interface- or abstract-class based implementors.
  • Support sync + async members (preserve signatures).

Motivation / Problem

Bridge implementations often repeat:

  • Abstraction storing implementor reference
  • Forwarding members
  • Optional refined abstractions
  • Naming collisions and inconsistent wiring

Generator can emit the canonical scaffolding once, consistently.


Supported Targets (must-have)

Bridge generation must support:

  • implementor contract: interface or abstract class
  • abstraction host: partial class / partial record class (struct support optional; v1 can support struct if desired)

V1 scope can focus on:

  • generating an abstraction base type that forwards to implementor
  • optional generation of a default abstraction implementation

Proposed User Experience

A) Annotate implementor contract, generate abstraction base

[BridgeImplementor]
public partial interface IRenderer
{
    void DrawLine(int x1, int y1, int x2, int y2);
    ValueTask FlushAsync(CancellationToken ct = default);
}

[BridgeAbstraction(typeof(IRenderer))]
public partial class Shape
{
    // user adds domain methods and calls into generated forwarding
}

Generated (representative shape):

public abstract partial class Shape
{
    protected Shape(IRenderer implementor);
    protected IRenderer Implementor { get; }

    protected void DrawLine(int x1, int y1, int x2, int y2)
        => Implementor.DrawLine(x1, y1, x2, y2);

    protected ValueTask FlushAsync(CancellationToken ct = default)
        => Implementor.FlushAsync(ct);
}

B) Generate a default refined abstraction (optional)

[BridgeAbstraction(typeof(IRenderer), GenerateDefault = true, DefaultTypeName = "DefaultShape")]
public partial class Shape { }

Generated:

  • DefaultShape : Shape with minimal constructor.

Attributes / Surface Area

Namespace: PatternKit.Generators.Bridge

Core

  • [BridgeImplementor] on implementor contract

    • string? ImplementorTypeName (optional; mostly marker)
  • [BridgeAbstraction(Type implementorType)] on abstraction host

    • string ImplementorPropertyName = "Implementor"
    • bool GenerateDefault (default: false)
    • string? DefaultTypeName (default: <AbstractionName>Default)

Optional:

  • [BridgeIgnore] for implementor members to exclude from generated forwarding.

Semantics (must-have)

Forwarding

  • Generated protected forwarding methods for each implementor member.
  • Preserve signatures (no rewriting).
  • For interface implementors, forward all members.
  • For abstract class implementors, forward only virtual/abstract members (v1).

Construction

  • Abstraction must store implementor reference.
  • Generated constructor should be protected.
  • Null checking: throw ArgumentNullException.

Async

  • Preserve implementor async signatures.
  • Do not rewrite Task/ValueTask; just forward.

Diagnostics (must-have)

  • PKBRG001 Type marked [BridgeAbstraction] must be partial.
  • PKBRG002 Implementor type must be interface or abstract class.
  • PKBRG003 Implementor member unsupported for forwarding (events v1).
  • PKBRG004 Name conflicts for generated default type.
  • PKBRG005 Inaccessible implementor members for forwarding.

Generated Code Layout

  • AbstractionName.Bridge.g.cs
  • AbstractionName.Bridge.Default.g.cs (optional)

Determinism:

  • stable ordering by member name.

Testing Expectations

  • Implementor calls are forwarded correctly.
  • Null implementor throws.
  • Diagnostics: invalid implementor type, name conflicts.
  • Async forwarding works.

Acceptance Criteria

  • Generates abstraction wiring and forwarding for implementor contract.
  • Works with interface and abstract class implementors.
  • Preserves signatures (sync and async).
  • Optional default refined abstraction generation.
  • Diagnostics and tests included.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions