Skip to content

Built-in Frames

JasperFx ships with several ready-to-use Frame implementations. These cover the most common code generation patterns so you rarely need to write custom frames for straightforward scenarios.

CommentFrame

Writes a single-line C# comment into the generated code. Useful for making generated source more readable.

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

    var type = assembly.AddType("Worker", typeof(IWorker));
    var method = type.MethodFor(nameof(IWorker.Execute));

    // CommentFrame writes a C# comment line
    method.Frames.Add(new CommentFrame("Begin processing"));
    method.Frames.Code("Console.WriteLine(\"Working...\");");
}

public interface IWorker
{
    void Execute();
}

snippet source | anchor

Generated output:

// Begin processing

CodeFrame

A general-purpose frame that writes a single statement from a format string. Variable placeholders are resolved automatically.

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

    var type = assembly.AddType("Processor", typeof(IProcessor));
    var method = type.MethodFor(nameof(IProcessor.Process));

    // CodeFrame uses a format string with variable placeholders
    method.Frames.Code("Console.WriteLine({0});", Use.Type<string>());
}

public interface IProcessor
{
    void Process(string input);
}

snippet source | anchor

The {0} placeholder is replaced by the resolved variable's Usage name. You can reference multiple variables with {1}, {2}, etc.

ReturnFrame

Generates a return statement, optionally returning a resolved variable.

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

    var type = assembly.AddType("Checker", typeof(IChecker));
    var method = type.MethodFor(nameof(IChecker.IsValid));

    method.Frames.Code("var result = {0} != null;", Use.Type<object>());

    // ReturnFrame generates "return <variable>;"
    method.Frames.Add(new ReturnFrame(typeof(bool)));
}

public interface IChecker
{
    bool IsValid(object input);
}

snippet source | anchor

  • new ReturnFrame() -- generates return; for void methods.
  • new ReturnFrame(typeof(bool)) -- resolves a bool variable and generates return <variable>;.
  • new ReturnFrame(variable) -- generates return <variable.Usage>; for a specific variable.

MethodCall

Generates a call to an existing method with full argument and return value resolution. This is the most commonly used frame and has its own dedicated page.

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

    var type = assembly.AddType("Invoker", typeof(IInvoker));
    var method = type.MethodFor(nameof(IInvoker.Invoke));

    // MethodCall generates a call to a static or instance method
    var call = new MethodCall(typeof(Console), nameof(Console.WriteLine));
    method.Frames.Add(call);
}

public interface IInvoker
{
    void Invoke(string message);
}

snippet source | anchor

See MethodCall for the full reference.

ConstructorFrame

Generates a new expression for a given type, resolving constructor arguments through the variable system.

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

    var type = assembly.AddType("ServiceBuilder", typeof(IServiceBuilder));
    var method = type.MethodFor(nameof(IServiceBuilder.Build));

    // ConstructorFrame generates "var widget = new Widget();"
    var ctor = new ConstructorFrame<Widget>(() => new Widget());
    method.Frames.Add(ctor);
}

public interface IServiceBuilder
{
    Widget Build();
}

public class Widget;

snippet source | anchor

The generic ConstructorFrame<T> variant accepts a lambda expression to identify the constructor. The generated code will be something like:

var widget = new Widget();

ConstructorCallMode

ModeGenerated Code
Variablevar x = new T(...); (default)
ReturnValuereturn new T(...);
UsingNestedVariableusing var x = new T(...);

IfBlock

Wraps inner frames in a conditional if block.

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

    var type = assembly.AddType("Guard", typeof(IGuard));
    var method = type.MethodFor(nameof(IGuard.Check));

    // IfBlock wraps inner frames in an if statement
    var inner = new CodeFrame(false, "Console.WriteLine(\"Input is not null\");");
    method.Frames.Add(new IfBlock("input != null", inner));
}

public interface IGuard
{
    void Check(object input);
}

snippet source | anchor

You can pass a string condition or a Variable (uses the variable's Usage property as the condition).

ThrowExceptionFrame

Generates a throw new ExceptionType(...) statement.

csharp
var frame = new ThrowExceptionFrame<InvalidOperationException>(someVariable);
// Generates: throw new System.InvalidOperationException(someVariable);

TemplateFrame

An abstract base for frames that use a template string with typed variable placeholders. Subclass it and override Template():

csharp
public class MyFrame : TemplateFrame
{
    protected override string Template()
    {
        var input = Arg<string>();
        return $"Console.WriteLine({input});";
    }
}

The Arg<T>() method creates a placeholder that the engine resolves to a real variable during code arrangement.

Summary

FramePurpose
CommentFrameWrites a // comment line
CodeFrameWrites a single statement from a format string
ReturnFrameWrites return; or return variable;
MethodCallCalls an existing method
ConstructorFrameCalls new T(...)
IfBlockWraps frames in if (condition) { }
ThrowExceptionFrame<T>Throws an exception
TemplateFrameTemplate-based code with typed placeholders

Released under the MIT License.