Skip to content

Local helper methods

Not every repeated snippet deserves a full component. Often you just want a local shortcut (a small private method, or even a local function), that removes noise from a single document-building method. This pattern is about readability at the smallest scale.

Without helpers, a method that builds a styled section repeats the same incantation:

section.Add(new Paragraph("Total revenue")
{ Style = new Style().Bold().WithForegroundColor(Color.FromRgb(0, 90, 160)) });
section.Add(new Paragraph("Net profit")
{ Style = new Style().Bold().WithForegroundColor(Color.FromRgb(0, 90, 160)) });
section.Add(new Paragraph("Operating margin")
{ Style = new Style().Bold().WithForegroundColor(Color.FromRgb(0, 90, 160)) });

When the shortcut is only needed inside a single method, a local function keeps it right where it’s used: no new class member, no scrolling:

public Document BuildSummary(Metrics m)
{
var doc = Document.Create("Summary");
var section = doc.AddSection();
var accent = Color.FromRgb(0, 90, 160);
Paragraph Metric(string label) =>
new Paragraph(label) { Style = new Style().Bold().WithForegroundColor(accent) };
section.Add(Metric("Total revenue"));
section.Add(Metric("Net profit"));
section.Add(Metric("Operating margin"));
return doc;
}

The local function Metric captures accent from the enclosing scope, so the shared color is defined once and the call sites stay short.

Private methods for cross-method shortcuts

Section titled “Private methods for cross-method shortcuts”

When the same shortcut is useful across several building methods in the same class, promote it to a private method:

public sealed class InvoiceBuilder
{
private static readonly Color Accent = Color.FromRgb(0, 90, 160);
private static Paragraph Label(string text) =>
new Paragraph(text) { Style = new Style().Bold().WithForegroundColor(Accent) };
private static Paragraph Value(string text, TextAlignment align = TextAlignment.Right) =>
new Paragraph(text) { Style = new Style().WithTextAlignment(align) };
public Document Build(Invoice invoice)
{
var doc = Document.Create($"Invoice {invoice.Number}");
var section = doc.AddSection();
section.Add(Label("Bill to"));
section.Add(Value(invoice.CustomerName, TextAlignment.Left));
// ...
return doc;
}
}

Helpers aren’t only for styling. A common use is folding repetitive content logic ( formatting a currency, building a key/value row) into one place:

private static TableRow MoneyRow(string label, decimal amount) =>
new TableRow()
.AddCell(label)
.AddCell(amount.ToString("C"));
var table = new Table().Header("Item", "Amount");
table.AddRow(MoneyRow("Subtotal", invoice.Subtotal));
table.AddRow(MoneyRow("Tax", invoice.Tax));
table.AddRow(MoneyRow("Total", invoice.Total));
Reach for…When
Local functionThe shortcut is used in exactly one method
Private methodThe shortcut is shared across methods in one class
ComponentThe piece is a meaningful, reusable unit of the document
Extension methodYou want a fluent shortcut available across the whole codebase

These are points on a spectrum from local to global. Start local (a local function costs nothing and is the easiest to delete) and promote only when reuse actually materializes.

  • Prefer the smallest scope that removes the duplication.
  • Capture shared constants (colors, fonts, indents) once and let helpers close over them.
  • Name by intent (Label, MoneyRow), not by mechanics (MakeBoldBlueParagraph).
  • Don’t over-abstract a helper used twice; two call sites is enough, three is plenty.