Skip to content

TypeBuilder

Create type declarations.

See also: Emit Overview | MethodBuilder | PropertyBuilder

Factory Methods

Method Description
Class(string name) Create a class
Interface(string name) Create an interface
Struct(string name) Create a struct
Record(string name) Create a record
Parse(string signature) Parse from signature (e.g., "public partial class MyClass")

Namespace & Usings

TypeBuilder
    .Class("MyClass")
    .InNamespace("MyApp.Domain")
    .AddUsing("System")
    .AddUsings("System.Collections.Generic", "System.Linq")

Accessibility & Modifiers

TypeBuilder
    .Class("MyClass")
    .WithAccessibility(Accessibility.Public)
    .WithAccessibility("public")  // from snapshot or ValidSymbol.AccessibilityString
    .AsStatic()
    .AsAbstract()
    .AsSealed()
    .AsPartial()

Type Parameters

// Simple type parameter
TypeBuilder
    .Class("Repository")
    .AddTypeParameter("T")

// Type parameter with constraints
TypeBuilder
    .Class("Repository")
    .AddTypeParameter("T", tp => tp.AsClass().WithNewConstraint())

// Multiple type parameters with mixed constraints
TypeBuilder
    .Class("Handler")
    .AddTypeParameter("T", tp => tp.AsClass())
    .AddTypeParameter("TResult", tp => tp.AsStruct())

// Parse generic signatures directly
TypeBuilder.Parse("public sealed class DbSetQuery<RT, T> where T : class")

Interfaces

TypeBuilder
    .Class("Repository")
    .Implements("IRepository")
    .Implements("IDisposable", "IAsyncDisposable")

// Conditional interfaces (see Directives for more)
TypeBuilder
    .Struct("UserId")
    .Implements("IEquatable<UserId>")
    .Implements("ISpanFormattable", Directives.Net6OrGreater)
    .Implements("IParsable<UserId>", Directives.Net7OrGreater)

Adding Members

// Properties
builder.AddProperty("Name", "string", prop => prop
    .WithAccessibility(Accessibility.Public)
    .WithAutoPropertyAccessors())
builder.AddProperty(propertyBuilder)

// Fields
builder.AddField("_name", "string", field => field
    .WithAccessibility(Accessibility.Private)
    .AsReadonly())
builder.AddField(fieldBuilder)

// Methods
builder.AddMethod("GetName", method => method
    .WithReturnType("string")
    .WithBody(body => body.AddReturn("_name")))
builder.AddMethod(methodBuilder)

// Constructors
builder.AddConstructor(ctor => ctor
    .AddParameter("name", "string")
    .WithBody(body => body.AddStatement("_name = name;")))
builder.AddConstructor(constructorBuilder)

// Primary constructors (records, C# 12+)
builder.WithPrimaryConstructor(ctor => ctor
    .AddParameter("name", "string"))

// Nested types
builder.AddNestedType("Inner", inner => inner
    .WithAccessibility(Accessibility.Private))
builder.AddNestedType(nestedTypeBuilder)

// Operators (see also: OperatorBuilder in other-builders.md)
builder.AddEqualityOperator("left.Equals(right)")
builder.AddInequalityOperator("!left.Equals(right)")
builder.AddOperator(OperatorBuilder.LessThan("MyType")
    .WithExpressionBody("left.Value < right.Value"))
builder.AddOperator(operatorBuilder)

// Conversion operators (see also: ConversionOperatorBuilder in other-builders.md)
builder.AddExplicitConversion("Guid", op => op
    .WithExpressionBody("new UserId(value)"))
builder.AddExplicitConversionTo("Guid", op => op
    .WithExpressionBody("value.Value"))
builder.AddImplicitConversion("string", op => op
    .WithExpressionBody("new Name(value)"))
builder.AddImplicitConversionTo("string", op => op
    .WithExpressionBody("value.Value"))
builder.AddConversionOperator(conversionOperatorBuilder)

Attributes

builder.WithAttribute("Serializable")
builder.WithAttribute("JsonProperty", attr => attr
    .WithArgument("\"name\"")
    .WithNamedArgument("Required", "true"))
builder.WithAttribute(attributeBuilder)

XML Documentation

builder.WithXmlDoc("Represents a customer entity.")

builder.WithXmlDoc(doc => doc
    .Summary("Represents a customer entity.")
    .Remarks("This class is generated by the source generator."))

builder.WithXmlDoc(existingXmlDocumentation)

Properties

builder.Name    // string — the type name
builder.Kind    // TypeKind — class, interface, struct, etc.

Emit

OptionalEmit result = builder.Emit();
OptionalEmit result = builder.Emit(EmitOptions.Default);

Region Support

Group members in #region/#endregion blocks using three approaches.

Auto-Regions

Enable UseRegions in EmitOptions to automatically wrap each member category:

TypeBuilder.Class("Customer")
    .AddField("_name", "string", f => f)
    .AddProperty("Name", "string", p => p.WithAutoPropertyAccessors())
    .AddMethod("GetName", m => m.WithExpressionBody("_name"))
    .Emit(new EmitOptions { UseRegions = true });

Generates #region Fields, #region Properties, #region Methods around each group.

Tag-Per-Member (InRegion)

Tag individual members with custom region names using .InRegion():

.AddProperty("Name", "string", p => p.WithAutoPropertyAccessors().InRegion("Identity"))
.AddProperty("Age", "int", p => p.WithAutoPropertyAccessors().InRegion("Demographics"))

Available on all member builders: PropertyBuilder, MethodBuilder, FieldBuilder, ConstructorBuilder, EventBuilder, OperatorBuilder, ConversionOperatorBuilder, IndexerBuilder.

Lambda Grouping (AddRegion)

Add multiple members to the same region in one call:

TypeBuilder.Class("Customer")
    .AddRegion("Identity", r => r
        .AddProperty("Name", "string", p => p.WithAutoPropertyAccessors())
        .AddProperty("Email", "string", p => p.WithAutoPropertyAccessors()))
    .AddRegion("Behavior", r => r
        .AddMethod("Validate", m => m.WithExpressionBody("true")))

Composing Approaches

All three compose naturally. Explicit tags override auto-regions for tagged members:

TypeBuilder.Class("Customer")
    .AddField("_name", "string", f => f)                    // auto: #region Fields
    .AddProperty("Name", "string", p => p
        .WithAutoPropertyAccessors().InRegion("Custom"))     // explicit: #region Custom
    .AddMethod("GetName", m => m.WithExpressionBody("_name"))// auto: #region Methods
    .Emit(new EmitOptions { UseRegions = true });