BodyBuilder¶
Build method, constructor, and property bodies with a fluent API for control flow, statements, and comments.
See also: Emit Overview | MethodBuilder | TypeRef & ExpressionRef | CatchBuilder | SwitchStatementBuilder | SwitchExpressionBuilder | CommentBuilder
Factory Methods¶
| Method | Description |
|---|---|
Empty() |
Create an empty body |
Statements¶
body.AddStatement("Console.WriteLine(\"Hello\")")
body.AddStatements("var a = 1;\nvar b = 2;") // multi-line string
body.AddReturn("result")
body.AddReturn() // void return
body.AddThrow("new InvalidOperationException()")
body.AddCustom(statementSyntax) // raw Roslyn StatementSyntax
Comments¶
body.AddComment("// Dispatch the event")
body.AddComment(c => c
.Line("First line")
.Line("Second line"))
Comments are attached as leading trivia on the next statement added.
Branching¶
If / If-Else¶
body.AddIf("user != null", b => b
.AddStatement("Process(user)"))
body.AddIfElse("user != null",
ifBody => ifBody.AddStatement("Process(user)"),
elseBody => elseBody.AddThrow("new ArgumentNullException()"))
Switch Statement¶
Traditional switch with case sections. Case bodies containing variable declarations are automatically wrapped in braces.
body.AddSwitch("job.JobType", sw => sw
.Case("\"create\"", cb => cb
.AddStatement("HandleCreate()")
.AddStatement("break"))
.Case("MyEvent e", cb => cb
.AddStatement("var payload = e.GetPayload()")
.AddStatement("await Process(payload)")
.AddReturn("true"))
.Default(cb => cb.AddReturn("false")))
Switch Expression¶
Emits return expr switch { ... };. Supports pattern matching arms, a discard default, and nested switches.
// Simple type-pattern switch
body.AddSwitchExpression("@event", sw => sw
.Arm("OrderCreated e", "HandleCreated(e)")
.Arm("OrderShipped e", "HandleShipped(e)")
.Default("Eff<Unit>.Pure(unit)"))
// Nested switch expression (e.g., dispatch on payload then sub-dispatch on action)
body.AddSwitchExpression("payload", sw => sw
.Arm("BlockActionsPayload ba", "ba.Actions switch", nested => nested
.Arm("[{ ActionId: \"approve\" } action, ..]", "HandleApprove(action)")
.Default("unitEff"))
.Default("new Acknowledge()"))
Loops¶
ForEach¶
While¶
body.AddWhile("!client.IsConnected && !token.IsCancellationRequested", b => b
.AddStatement("await Task.Delay(500, token)"))
For¶
Do-While¶
body.AddDoWhile("hasMore", b => b
.AddStatement("item = ReadNext()")
.AddStatement("hasMore = item != null"))
Yield¶
Lock¶
Error Handling¶
Try / Catch¶
body.AddTryCatch(
tryBody => tryBody
.AddStatement("await DoWork()"),
catches => catches
.Catch("Exception", "ex", cb => cb
.AddStatement("logger.LogError(ex, \"Error\")"))
.CatchAll(cb => cb
.AddStatement("logger.LogError(\"Unknown error\")")))
Try / Catch / Finally¶
body.AddTryCatchFinally(
tryBody => tryBody.AddStatement("connection.Open()"),
catches => catches.Catch("Exception", "ex", cb => cb
.AddStatement("logger.LogError(ex, \"Connection error\")")),
finallyBody => finallyBody.AddStatement("connection.Close()"))
The CatchBuilder supports:
| Method | Description |
|---|---|
Catch(TypeRef type, string name, ...) |
Catch a typed exception |
CatchAll(...) |
Parameterless catch clause |
CatchWhen(TypeRef type, string name, string condition, ...) |
Catch with when filter |
Resource Management¶
Block-Scoped Using¶
body.AddUsing("var scope = factory.CreateScope()", b => b
.AddStatement("var service = scope.ServiceProvider.GetService<IMyService>()")
.AddStatement("await service.DoWork()"))
For declaration-style usings (using var x = ...), use AddStatement directly:
Await Using¶
body.AddAwaitUsing("var conn = await GetConnectionAsync()", b => b
.AddStatement("await conn.ExecuteAsync(sql)"))
For declaration-style (await using var x = ...), use AddStatement directly.
Local Functions¶
body.AddLocalFunction(m => m
.AsStatic()
.WithReturnType("int")
.AddParameter("a", "int")
.AddParameter("b", "int")
.WithExpressionBody("a + b"), "Add")
The configure callback receives a MethodBuilder. Access modifiers are omitted automatically (local functions don't have them).
Conditional Compilation¶
Wrap statements in #if/#endif directives:
body.When(Directive.Net8OrGreater, b => b
.AddStatement("IParsable<T>.TryParse(input, out var result)"))
Properties¶
| Property | Type | Description |
|---|---|---|
IsEmpty |
bool |
Whether the body has no statements |
Statements |
ImmutableArray<StatementSyntax> |
The collected statements |
PendingTrivia |
ImmutableArray<SyntaxTrivia> |
Comments waiting to attach |