Skip to content

Code Generation Overview

JasperFx includes a runtime code generation framework that builds and compiles C# classes on the fly. This is the same engine that powers the middleware pipelines in Wolverine and the document session internals in Marten.

Why Runtime Code Generation?

Many frameworks rely on reflection or expression trees to wire up handlers, middleware, and data access at runtime. JasperFx takes a different approach: it generates actual C# source code, then compiles it using Roslyn. The result is code that runs at the same speed as hand-written C# with full debuggability -- you can inspect the generated source and set breakpoints in it.

Key benefits:

  • Performance -- generated code compiles to native IL with no reflection overhead at invocation time.
  • Transparency -- you can preview the exact C# that will be generated before it runs.
  • Extensibility -- the frame model lets library authors compose code from reusable building blocks.

Architecture

The code generation system is organized around a small set of core concepts:

ConceptPurpose
GeneratedAssemblyTop-level container. Holds one or more types and produces the final C# source file.
GeneratedTypeA single class to be generated. Can inherit from a base class or implement interfaces.
GeneratedMethodA method within a generated type. Holds the ordered collection of Frames.
FrameA unit of code generation. Each frame writes one or more lines of C# into the method body.
VariableRepresents a C# variable flowing through frames. Tracks type, name, and which frame creates it.

Quick Example

cs
public static string GenerateGreeterCode()
{
    var rules = new GenerationRules("MyApp.Generated");
    var assembly = new GeneratedAssembly(rules);

    // Add a new type that implements IGreeter
    var type = assembly.AddType("HelloGreeter", typeof(IGreeter));

    // Get the method defined by the interface
    var method = type.MethodFor("Greet");

    // Add a frame that writes a line of code
    method.Frames.Code("return \"Hello, \" + {0};", Use.Type<string>());

    // Generate the C# source code
    var code = assembly.GenerateCode();

    return code;
}

public interface IGreeter
{
    string Greet(string name);
}

snippet source | anchor

How It Works

  1. Create a GeneratedAssembly with a set of GenerationRules.
  2. Add one or more GeneratedType entries, specifying base classes or interfaces.
  3. Retrieve GeneratedMethod instances (discovered from the base type or added manually).
  4. Populate each method with Frame objects that describe the code to generate.
  5. Call GenerateCode() to produce the C# source text.
  6. Optionally compile the assembly at runtime to get live Type instances.

TypeLoadMode

JasperFx supports three strategies for loading generated types, controlled by the TypeLoadMode enum on GenerationRules:

ModeBehavior
DynamicAlways generate and compile at runtime. Best for development.
AutoTry to load pre-built types from the application assembly; fall back to runtime generation.
StaticTypes must exist in the pre-built assembly. Throws if missing. Fastest startup.

See CLI: codegen Command for tooling that writes generated code ahead of time.

Next Steps

Released under the MIT License.