Skip to content

EmitWriter

A C#-aware text writer for source generator output. Replaces SyntaxFactory + NormalizeWhitespace() with ~100-460x better performance and ~36x less memory allocation.

See also: Emit Overview | IWritable | PartialTypeHierarchy


Constructor

using var writer = new EmitWriter(indentation: "    ", endOfLine: "\n");
Parameter Type Default Description
indentation string " " Indentation string per level (4 spaces)
endOfLine string "\n" Line ending string

EmitWriter implements IDisposable. Use using var or using blocks.

Core Writing

Method Description
Write(string text) Write text (applies indentation at line start)
WriteLine(string text) Write text followed by a newline
WriteLine() Write an empty line (no indentation)
Write(IWritable writable) Delegate to an IWritable component's WriteTo method

All methods return this for fluent chaining.

Indentation

Method / Property Description
Indent() Increase indentation by one level
Outdent() Decrease indentation by one level
IndentLevel int — current indentation depth

Indentation is applied automatically when writing at the start of a line.

Block Helpers

Method Description
Block(bool trailingSemicolon = false) Write {, indent, return IDisposable that writes } (or };) and outdents
Block(string declaration, bool trailingSemicolon = false) Write declaration, then open block
// Block with declaration
using (writer.Block("public class Foo"))
{
    writer.WriteLine("public int Value { get; set; }");
}
// Produces:
// public class Foo
// {
//     public int Value { get; set; }
// }

// Trailing semicolon (enum, record with body)
using (writer.Block("public enum Status", trailingSemicolon: true))
{
    writer.WriteLine("Active,");
    writer.WriteLine("Inactive,");
}
// Produces:
// public enum Status
// {
//     Active,
//     Inactive,
// };

C# Helpers

Method Description
Comment(string text) Write // text
XmlDoc(string tag, string content) Write /// <tag>content</tag>
XmlDocBlock(string tag, IEnumerable<string> lines) Write multi-line /// <tag> block
Attribute(string attribute) Write [attribute]
NullableEnable() Write #nullable enable
IfDirective(string condition) Write #if condition
EndIfDirective() Write #endif
Region(string name) Write #region name
EndRegion() Write #endregion
Using(string ns) Write using ns;
GlobalUsing(string ns) Write global using ns;

Fluent Chaining

All methods return this:

writer
    .Comment("<auto-generated/>")
    .NullableEnable()
    .WriteLine()
    .Using("System")
    .Using("System.Collections.Generic")
    .WriteLine();

Complete Example

using var writer = new EmitWriter();
writer.Comment("<auto-generated/>");
writer.NullableEnable();
writer.WriteLine();

writer.Using("System");
writer.WriteLine();

writer.XmlDoc("summary", "A generated service.");
using (writer.Block("public sealed class MyService"))
{
    writer.XmlDoc("summary", "Gets the name.");
    writer.WriteLine("public string Name { get; }");
    writer.WriteLine();

    writer.XmlDoc("summary", "Creates a new instance.");
    using (writer.Block("public MyService(string name)"))
    {
        writer.WriteLine("Name = name;");
    }
}

context.AddSource("MyService.g.cs", writer.ToString());

Output

Member Description
ToString() Returns the accumulated output as a string
Dispose() Disposes the underlying StringWriter

Thread Safety

Not thread-safe. Each generator output step should create its own EmitWriter instance.