OmniNet.SourceGenerators.Core 0.1.10

dotnet add package OmniNet.SourceGenerators.Core --version 0.1.10
                    
NuGet\Install-Package OmniNet.SourceGenerators.Core -Version 0.1.10
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="OmniNet.SourceGenerators.Core" Version="0.1.10" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="OmniNet.SourceGenerators.Core" Version="0.1.10" />
                    
Directory.Packages.props
<PackageReference Include="OmniNet.SourceGenerators.Core" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add OmniNet.SourceGenerators.Core --version 0.1.10
                    
#r "nuget: OmniNet.SourceGenerators.Core, 0.1.10"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package OmniNet.SourceGenerators.Core@0.1.10
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=OmniNet.SourceGenerators.Core&version=0.1.10
                    
Install as a Cake Addin
#tool nuget:?package=OmniNet.SourceGenerators.Core&version=0.1.10
                    
Install as a Cake Tool

OmniNet.SourceGenerators.Core

A core library providing fluent builders and helpers for creating C# source generators with ease. Write source generators with minimal boilerplate using a type-safe, performant API designed for zero-allocation builder patterns.

Installation

dotnet add package OmniNet.SourceGenerators.Core

NuGet Build Status

Features

  • Zero-allocation builders - Uses readonly ref struct for stack allocation and maximum performance
  • Fluent API - Chainable methods for intuitive, readable code generation
  • Type-safe - Leverage C#'s type system to catch errors at compile time
  • Comprehensive - Generate classes, interfaces, structs, records, properties, methods, nested types, and more
  • Incremental generator support - Built for modern incremental source generators
  • Fully tested - 65+ unit tests ensuring reliability and correctness

Core Builders

  • SourceBuilder - Entry point for generating C# source code files
  • OpeningTypeBuilder - Configure type declarations (class, interface, struct, record) with modifiers
  • TypeBuilder - Build type members (properties, methods, etc.) within a type
  • PropertyBuilder - Generate properties with modifiers, accessors, initializers, and attributes
  • MethodBuilder - Generate methods with modifiers, parameters, and bodies
  • MethodParametersBuilder - Define method parameters (including ref/out/in/params/defaults)
  • MethodBodyBuilder - Write method bodies (statements, return, throw, etc.)
  • TypeInheritanceBuilder - Specify base classes and interfaces

Utilities

  • TypeReference - Flexible type specification (from ITypeSymbol, string, or namespace+name)
  • IncrementalSymbolValuesProvider - Helper for creating incremental source generators
  • SourceGeneratorProvider - Access generated attributes stored as assembly resources

Quick Start

1. Define your generator attribute

Create an attribute class in an Attributes folder in your generator project:

[AttributeUsage(AttributeTargets.Class)]
public sealed class MyGenerateAttribute : Attribute { }

2. Create your incremental generator

using OmniNet.SourceGenerators.Core;

[Generator]
public class MyGenerator : IIncrementalGenerator
{
    private static readonly IGeneratorAttribute _attribute = 
        SourceGeneratorProvider.GetAttribute<MyGenerateAttribute>();

    public void Initialize(IncrementalGeneratorInitializationContext context)
    {
        // Register the attribute source code
        context.RegisterPostInitializationOutput(ctx => ctx.AddSource(_attribute));

        // Find all classes with the attribute
        var items = context.SyntaxProvider
            .ForTypeWithAttribute(_attribute)
            .Transform((symbol, attributes, ct) => symbol);

        context.RegisterSourceOutput(items, GenerateSource);
    }

    private static void GenerateSource(SourceProductionContext context, ITypeSymbol typeSymbol)
    {
        var sb = new SourceBuilder();

        using var type = sb
            .AppendFileNamespace(typeSymbol.ContainingNamespace)
            .BuildClass(typeSymbol.Name)
            .WithAccessibility(typeSymbol.DeclaredAccessibility)
            .WithPartial()
            .Append()
            .AppendOpenType();

        // Add properties using PropertyBuilder - with string type
        type.BuildProperty("string", "GeneratedProperty")
            .WithAccessibility(Accessibility.Public)
            .WithImplicitGetter()
            .WithImplicitSetter()
            .Append();

        // Add methods using MethodBuilder - with string return type
        type.BuildMethod("GetName", "string")
            .WithAccessibility(Accessibility.Public)
            .OpenParameters()
            .OpenBody()
                .AppendReturn("GeneratedProperty")
            .Dispose();

        type.BuildMethod("SetValue")
            .WithAccessibility(Accessibility.Public)
            .OpenParameters()
                .AddParameter("string", "key")
                .AddParameter("int", "value", "0")
            .OpenBody()
                .AppendLine("// Set value logic")
            .Dispose();

        type.BuildMethod("ToString", "string")
            .WithAccessibility(Accessibility.Public)
            .WithOverride()
            .OpenParameters()
            .AppendExpression("$\"Generated: {GeneratedProperty}\"");

        sb.AddToContext(context, TypeReference.FromSymbol(typeSymbol));
    }
}

API Reference

SourceBuilder

Entry point for generating source code files.

var sb = new SourceBuilder();

// Add file-scoped namespace
sb.AppendFileNamespace(namespaceSymbol);

// Start building a class or interface
sb.BuildClass("MyClass");
sb.BuildInterface("IMyInterface");

// Add generated source to compilation
sb.AddToContext(context, TypeReference.FromSymbol(typeSymbol));
sb.AddToContext(context, namespaceSymbol, "FileName", "suffix");

TypeReference

Represents a type that can be specified in multiple ways:

// Option 1: From ITypeSymbol (use factory method)
var stringType = compilation.GetSpecialType(SpecialType.System_String);
type.BuildProperty(TypeReference.FromSymbol(stringType), "Name");

// Option 2: Plain string (implicit conversion - recommended for simplicity)
type.BuildProperty("string", "Name");
type.BuildProperty("int", "Count");

// Option 3: Fully qualified string (implicit conversion)
type.BuildProperty("global::System.Collections.Generic.List<int>", "Numbers");

// Option 4: Namespace + type name tuple (implicit conversion)
var myNamespace = compilation.GetCompilationNamespace("MyCompany.Domain");
type.BuildProperty((myNamespace, "CustomEntity"), "Entity");
type.BuildProperty((myNamespace, "Repository<T>"), "Repo");

OpeningTypeBuilder

Configures type declaration with modifiers.

sb.BuildClass("MyClass")
    .WithAccessibility(Accessibility.Public)
    .WithPartial()
    .Append()           // Returns TypeInheritanceBuilder
    .AppendOpenType();  // Returns TypeBuilder

TypeBuilder

Generates type members within a type declaration. All builder methods accept TypeReference for specifying types.

using var type = /* ... */.AppendOpenType();

// Build properties using string type (implicit conversion - simplest)
type.BuildProperty("string", "PropertyName")
    .WithAccessibility(Accessibility.Public)
    .WithImplicitGetter()
    .WithImplicitSetter()
    .Append();

// Build properties using ITypeSymbol (when working with Roslyn symbols)
var stringType = compilation.GetSpecialType(SpecialType.System_String);
type.BuildProperty(stringType, "PropertyName")  // Overload accepts ITypeSymbol directly
    .WithAccessibility(Accessibility.Public)
    .WithImplicitGetter()
    .WithImplicitSetter()
    .Append();

// Build void method
type.BuildMethod("MethodName")
    .WithAccessibility(Accessibility.Public)
    .OpenParameters()
    .OpenBody()
        .AppendLine("// method body")
    .Dispose();

// Build method with return type (string)
type.BuildMethod("MethodName", "int")
    .WithAccessibility(Accessibility.Public)
    .OpenParameters()
    .OpenBody()
        .AppendReturn("42")
    .Dispose();

// Build method with ITypeSymbol return type
type.BuildMethod("GetValue", intSymbol)  // Overload accepts ITypeSymbol directly
    .WithAccessibility(Accessibility.Public)
    .OpenParameters()
    .AppendExpression("42");

// Build nested types
using var nestedType = type.BuildNestedClass("NestedClass")
    .WithAccessibility(Accessibility.Public)
    .Append()
    .AppendOpenType();

nestedType.BuildProperty("string", "NestedProperty")
    .WithAccessibility(Accessibility.Public)
    .WithImplicitGetter()
    .Append();

// Nested types can be nested further
using var deeplyNested = nestedType.BuildNestedClass("DeeplyNestedClass")
    .WithAccessibility(Accessibility.Private)
    .Append()
    .AppendOpenType();

// All nested type methods available:
// - BuildNestedClass(name)
// - BuildNestedInterface(name)
// - BuildNestedStruct(name)
// - BuildNestedRecord(name)
// - BuildNestedRecordStruct(name)

// Multiple members are automatically separated by blank lines
type.BuildProperty("int", "Age")
    .WithAccessibility(Accessibility.Public)
    .WithImplicitGetter()
    .WithImplicitSetter()
    .Append();

type.BuildProperty("string", "Name")
    .WithAccessibility(Accessibility.Public)
    .WithImplicitGetter()
    .WithImplicitSetter()
    .Append();
// Generates:
// public int Age { get; set; }
//
// public string Name { get; set; }

Note: TypeBuilder implements IDisposable to close the type braces. Always use using var type = ... or manually call type.Dispose() when done. This applies to both top-level and nested types.

MethodBuilder

Configures method generation with full control over modifiers, parameters, and body. All type parameters accept TypeReference.

type.BuildMethod("Name")
    .WithAccessibility(Accessibility.Public)
    .WithStatic()
    .WithAsync()
    .WithVirtual() // or .WithOverride(), .WithAbstract()
    .WithNew()
    .WithInheritDoc(TypeReference.FromSymbol(baseType), "MethodName")
    .WithAttributes(attributeDataArray)
    .OpenParameters()
        .AddParameter("string", "param")
        .AddRefParameter("int", "refParam")
        .AddOutParameter("bool", "outParam")
        .AddParamsParameter("object", "paramsArray")
    .OpenBody()
        .AppendLine("// method body")
        .AppendReturn("value")
    .Dispose();

// Expression-bodied method
 type.BuildMethod("ToString", "string")
    .WithAccessibility(Accessibility.Public)
    .WithOverride()
    .OpenParameters()
    .AppendExpression("$\"Name: {Property}\"");

// Abstract/interface method
 type.BuildMethod("Calculate", "int")
    .WithAccessibility(Accessibility.Public)
    .WithAbstract()
    .OpenParameters()
        .AddParameter("int", "x")
    .AppendAbstract();

// Explicit interface implementation
type.BuildMethod("ToString", "string")
    .WithExplicitInterfaceImplementation("System.IFormattable")
    .OpenParameters()
        .AddParameter("string", "format")
        .AddParameter("System.IFormatProvider", "formatProvider")
    .OpenBody()
        .AppendReturn("\"formatted string\"")
    .Dispose();
// Generates: string System.IFormattable.ToString(string format, System.IFormatProvider formatProvider) { ... }

MethodParametersBuilder

Builder for method parameters. All type parameters accept TypeReference.

.OpenParameters()
    .AddParameter("string", "name")
    .AddParameter("int", "count", "0")  // with default value
    .AddRefParameter("bool", "refName")
    .AddOutParameter("decimal", "outName")
    .AddInParameter("ReadOnlySpan<char>", "inName")
    .AddParamsParameter("object", "paramsName")
    .AddParametersFrom(methodSymbol)  // copy from existing method

MethodBodyBuilder

Builder for method body.

.OpenBody()
    .AppendLine("// code")
    .AppendReturn("expression")
    .AppendThrow("new Exception()")
    .Dispose();

PropertyBuilder

Configures property generation with full control over modifiers and accessors. Property type accepts TypeReference.

// Using string type (implicit conversion - simplest)
type.BuildProperty("string", "Name")
    .WithAccessibility(Accessibility.Public)
    .WithRequired()                              // required modifier
    .WithNew()                                   // new modifier
    .WithVirtual()                               // virtual modifiers (or WithOverride, WithAbstract)
    .WithImplicitGetter()                        // { get; }
    .WithImplicitSetter(initOnly: true)          // { init; }
    .WithInheritDoc("BaseTypeName", "PropertyName")  // inheritdoc
    .WithAttributes(attributeDataArray)          // copy attributes
    .Append();

// Using ITypeSymbol
var stringType = compilation.GetSpecialType(SpecialType.System_String);
type.BuildProperty(TypeReference.FromSymbol(stringType), "Name")
    .WithAccessibility(Accessibility.Public)
    .WithImplicitGetter()
    .WithImplicitSetter()
    .Append();

// Using namespace + type name
type.BuildProperty((myNamespace, "CustomType"), "Custom")
    .WithAccessibility(Accessibility.Public)
    .WithImplicitGetter()
    .Append();

SourceGeneratorProvider

Provides access to attributes embedded as assembly resources.

// Get handle to generated attribute
IGeneratorAttribute attribute = SourceGeneratorProvider.GetAttribute<MyAttribute>();

// Use in post-initialization
context.RegisterPostInitializationOutput(ctx => ctx.AddSource(attribute));

// Use for finding attributed symbols
context.SyntaxProvider.ForAttributeWithMetadataName(attribute.TypeFullName, ...);

Extension Methods

// Add attribute source to context
context.AddSource(generatorAttribute);

// Create provider for types with attribute
syntaxProvider.ForTypeWithAttribute(attribute);

// Check if namespace is global
namespaceSymbol.IsGlobal();
namespaceSymbol.IsNotGlobal();

Testing

This library includes comprehensive unit tests covering all major functionality:

  • PropertyBuilderTests - 17 tests covering property generation scenarios
  • MethodBuilderTests - 21 tests covering method generation scenarios
  • TypeBuilderTests - 21 tests covering type creation and member building
  • NestedTypeBuilderTests - 15 tests covering nested type generation scenarios

Run tests with:

dotnet test

All tests verify generated syntax is correct and follows C# conventions.

Performance

This library is designed with performance in mind:

  • Zero-allocation builders - All builders use readonly ref struct to avoid heap allocations
  • No LINQ in hot paths - Direct iteration for maximum performance
  • StringBuilder reuse - Efficient string building with minimal allocations
  • Span<T> usage - Uses modern C# features for zero-copy operations where applicable

Examples

Nested Types

Generate nested types with full support for all type kinds and access modifiers:

var sb = new SourceBuilder();

using var outerClass = sb.BuildClass("Container")
    .WithAccessibility(Accessibility.Public)
    .WithPartial()
    .Append()
    .AppendOpenType();

// Add property to outer class
outerClass.BuildProperty("string", "Name")
    .WithAccessibility(Accessibility.Public)
    .WithImplicitGetter()
    .WithImplicitSetter()
    .Append();

// Create nested class with private accessibility
using var nestedClass = outerClass.BuildNestedClass("Data")
    .WithAccessibility(Accessibility.Private)
    .Append()
    .AppendOpenType();

nestedClass.BuildProperty("int", "Value")
    .WithAccessibility(Accessibility.Public)
    .WithImplicitGetter()
    .Append();

// Create nested struct
using var nestedStruct = outerClass.BuildNestedStruct("Settings")
    .WithAccessibility(Accessibility.Public)
    .Append()
    .AppendOpenType();

nestedStruct.BuildProperty("bool", "IsEnabled")
    .WithAccessibility(Accessibility.Public)
    .WithImplicitGetter()
    .WithImplicitSetter()
    .Append();

// Generates:
// public partial class Container
// {
//     public string Name { get; set; }
//
//     private class Data
//     {
//         public int Value { get; }
//     }
//
//     public struct Settings
//     {
//         public bool IsEnabled { get; set; }
//     }
// }

Nested Type Methods:

  • BuildNestedClass(string name) - Create nested class
  • BuildNestedInterface(string name) - Create nested interface
  • BuildNestedStruct(string name) - Create nested struct
  • BuildNestedRecord(string name) - Create nested record
  • BuildNestedRecordStruct(string name) - Create nested record struct

Access Modifiers:

  • Nested types in classes support all modifiers: public, private, protected, internal, protected internal, private protected
  • Nested types in structs support: public, private, internal (protected modifiers not allowed)
  • Default accessibility for nested types is private (unlike top-level types which default to internal)

See the test/OmniNet.SourceGenerators.Core.Tests.Generator project for a complete working example of a source generator using this library.

Requirements

  • .NET Standard 2.0 (main library)
  • .NET 10.0 (test projects)
  • Microsoft.CodeAnalysis.CSharp 4.0.1+

Repository

License

MIT License - see LICENSE for details.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.10 128 1/22/2026
0.1.9 136 1/20/2026
0.1.8 121 1/18/2026
0.1.7 113 1/17/2026
0.1.6 130 1/15/2026
0.1.5 134 12/27/2025
0.1.4 289 12/18/2025
0.1.3 293 12/18/2025
0.1.2 299 12/18/2025
0.1.1 294 12/17/2025
0.1.0 181 2/23/2025