Skip to main content
Utilities for generating C# source code in source generators.

IndentedStringBuilder

Automatic indentation management:
var sb = new IndentedStringBuilder();

// Basic output
sb.AppendLine("namespace MyNamespace");
using (sb.BeginBlock())                    // { with indent
{
    sb.AppendLine("public class MyClass");
    using (sb.BeginBlock())
    {
        sb.AppendLine("// code here");
    }
}                                          // } with dedent

var code = sb.ToString();

Block Helpers

// Namespace
using (sb.BeginNamespace("MyNamespace"))
{
    // Inside namespace
}

// Class
using (sb.BeginClass("public partial", "MyClass"))
{
    // Inside class
}

// Class with base
using (sb.BeginClass("public", "MyClass", "BaseClass"))
{
    // Inside class
}

// Method
using (sb.BeginMethod("public", "void", "Execute"))
{
    // Inside method
}

// Method with parameters
using (sb.BeginMethod("public async", "Task", "RunAsync", "CancellationToken ct"))
{
    // Inside method
}

Control Structures

// If
using (sb.BeginIf("condition"))
{
    sb.AppendLine("// then branch");
}

// If-else
using (sb.BeginIf("condition"))
{
    sb.AppendLine("// then branch");
}
using (sb.BeginElse())
{
    sb.AppendLine("// else branch");
}

// ForEach
using (sb.BeginForEach("var", "item", "collection"))
{
    sb.AppendLine("// loop body");
}

GeneratedCodeHelpers

Standard attributes and pragmas for generated code:
// Nullable context
GeneratedCodeHelpers.NullableEnable      // "#nullable enable"
GeneratedCodeHelpers.NullableDisable     // "#nullable disable"
GeneratedCodeHelpers.NullableRestore     // "#nullable restore"

// Auto-generated header
GeneratedCodeHelpers.AutoGeneratedHeader("MyGenerator")
// Returns: "// <auto-generated by MyGenerator />"

// Attributes
GeneratedCodeHelpers.GeneratedCodeAttribute("MyGenerator", "1.0.0")
// [GeneratedCode("MyGenerator", "1.0.0")]

GeneratedCodeHelpers.ExcludeFromCodeCoverage
// [ExcludeFromCodeCoverage]

GeneratedCodeHelpers.EditorBrowsableNever
// [EditorBrowsable(EditorBrowsableState.Never)]

GeneratedCodeHelpers.DebuggerNonUserCode
// [DebuggerNonUserCode]

GeneratedCodeHelpers.CompilerGenerated
// [CompilerGenerated]

// Warning suppression
GeneratedCodeHelpers.SuppressWarnings("CS1591", "CS0618")
// #pragma warning disable CS1591, CS0618

GeneratedCodeHelpers.RestoreWarnings("CS1591", "CS0618")
// #pragma warning restore CS1591, CS0618

Complete Example

public static string GenerateClass(ClassModel model)
{
    var sb = new IndentedStringBuilder();

    sb.AppendLine(GeneratedCodeHelpers.AutoGeneratedHeader("MyGenerator"));
    sb.AppendLine(GeneratedCodeHelpers.NullableEnable);
    sb.AppendLine();

    using (sb.BeginNamespace(model.Namespace))
    {
        sb.AppendLine(GeneratedCodeHelpers.GeneratedCodeAttribute("MyGenerator", "1.0"));
        sb.AppendLine(GeneratedCodeHelpers.ExcludeFromCodeCoverage);

        using (sb.BeginClass("public partial", model.Name))
        {
            foreach (var property in model.Properties)
            {
                sb.AppendLine($"public {property.Type} {property.Name} {{ get; set; }}");
            }

            sb.AppendLine();

            using (sb.BeginMethod("public", "void", "Validate"))
            {
                foreach (var property in model.Properties.Where(p => p.Required))
                {
                    using (sb.BeginIf($"{property.Name} == null"))
                    {
                        sb.AppendLine($"throw new ArgumentNullException(nameof({property.Name}));");
                    }
                }
            }
        }
    }

    return sb.ToString();
}

EquatableArray

Value-equal array for generator caching:
// Convert
var equatable = immutableArray.AsEquatableArray();

// Use in models
public record MyModel(string Name, EquatableArray<string> Items);

// Compare (value equality)
if (array1.Equals(array2))
{
    // Arrays have same contents
}

HashCombiner

Combine hash codes (Murmur3):
var hash = HashCombiner.Create();
hash.Add(value1);
hash.Add(value2);
hash.AddRange(collection);
var code = hash.HashCode;