BB84.SourceGenerators

A collection of C# source generators that automatically generate boilerplate code at compile time, reducing manual coding and improving code maintainability.

CI CD CodeQL Dependabot

License: MIT C# .NET Standard 2.0 Issues LastCommit PullRequests RepoSize NuGet

Features

This package provides fourteen powerful source generators:

Installation

Install the package via NuGet:

dotnet add package BB84.SourceGenerators

Or via Package Manager Console:

Install-Package BB84.SourceGenerators

Usage

1. Enumerator Extensions Generator

Generates high-performance extension methods for enumerations, providing faster alternatives to Enum.ToString(), Enum.IsDefined(), Enum.GetNames(), and Enum.GetValues().

Attribute

[GenerateEnumeratorExtensions]

Example

using BB84.SourceGenerators.Attributes;

[GenerateEnumeratorExtensions]
public enum Status
{
    [System.ComponentModel.Description("Pending approval")]
    Pending = 0,
    Active = 1,
    [System.ComponentModel.Description("Temporarily inactive")]
    Inactive = 2,
    Deleted = 3
}

Generated Methods

The generator creates the following extension methods:

Usage Example

var status = Status.Pending;

// Fast string conversion
string name = status.ToStringFast(); // "Pending"

// Check if defined
bool isDefined = status.IsDefinedFast(); // true
bool isNameDefined = "Active".IsDefinedFast(); // true

// Get description
string description = status.GetDescriptionFast(); // "Pending approval"

// Get all names and values
IEnumerable<string> names = status.GetNamesFast();
IEnumerable<Status> values = status.GetValuesFast();

2. Notification Properties Generator

Automatically generates properties with INotifyPropertyChanged and/or INotifyPropertyChanging support for private fields in a class. Both interfaces are independently configurable.

Attribute

[GenerateNotifications(bool propertyChanged = true, bool propertyChanging = true, bool hasChanged = false)]

Parameters:

Example

using BB84.SourceGenerators.Attributes;

[GenerateNotifications(hasChanged: true)]
public partial class Person
{
    private int _id;
    private string _name;
    private string _email;
    private DateTime _createdAt;
    private DateTime? _updatedAt;

    public Person(int id, string name, string email)
    {
        _id = id;
        _name = name;
        _email = email;
        _createdAt = DateTime.UtcNow;
    }
}

Generated Code

The generator creates:

Usage Example

var person = new Person(1, "John Doe", "john@example.com");

// Subscribe to change notifications
person.PropertyChanging += (s, e) => Console.WriteLine($"Property {e.PropertyName} is changing");
person.PropertyChanged += (s, e) => Console.WriteLine($"Property {e.PropertyName} has changed");

// Change a property - events will fire automatically
person.Name = "Jane Doe";
person.Email = "jane@example.com";

// Check if object has been modified (when hasChanged: true)
if (person.HasChanged)
{
    Console.WriteLine("Person has been modified");
}

// Only INotifyPropertyChanged (no PropertyChanging events)
[GenerateNotifications(propertyChanging: false)]
public partial class LightweightModel
{
    private string _name;
}

// Works correctly with sealed classes
[GenerateNotifications]
public sealed partial class SealedModel
{
    private int _value;
}

3. Abstraction Generator

Generates interface and implementation classes for static classes, making them testable through dependency injection.

Attribute

[GenerateAbstraction(Type targetType, Type abstractionType, Type implementationType, params string[] excludeMethods)]

Parameters:

Example

using BB84.SourceGenerators.Attributes;

// Generate abstraction for System.IO.File
[GenerateAbstraction(typeof(File), typeof(IFileProvider), typeof(FileProvider))]
public partial class FileProvider
{ }

public partial interface IFileProvider
{ }

Generated Code

The generator creates:

Usage Example

// In your service
public class DocumentService
{
    private readonly IFileProvider _fileProvider;

    public DocumentService(IFileProvider fileProvider)
        => _fileProvider = fileProvider;

    public string ReadDocument(string path)
        => _fileProvider.ReadAllText(path);
}

// In your DI container setup
services.AddSingleton<IFileProvider, FileProvider>();

// In tests, you can mock IFileProvider
var mockFileProvider = new Mock<IFileProvider>();
mockFileProvider.Setup(x => x.ReadAllText(It.IsAny<string>())).Returns("test content");

4. INI File Generator

Generates static Read and Write methods for classes, enabling compile-time INI file serialization and deserialization based on decorated properties.

Attributes

[GenerateIniFile(StringComparison stringComparison = StringComparison.OrdinalIgnoreCase, string sectionDelimiter = ".")]
[GenerateIniFileSection(string? name = null)]
[GenerateIniFileValue(string? name = null)]

Parameters:

Supported Value Types: string, int, long, float, double, bool, decimal, DateTime

Example

using BB84.SourceGenerators.Attributes;

[GenerateIniFile]
public partial class AppConfig
{
    [GenerateIniFileSection("General")]
    public GeneralSection General { get; set; }

    [GenerateIniFileSection("Database")]
    public DatabaseSection Database { get; set; }
}

public class GeneralSection
{
    [GenerateIniFileValue("AppName")]
    public string ApplicationName { get; set; }

    [GenerateIniFileValue("Version")]
    public int ApplicationVersion { get; set; }

    [GenerateIniFileValue("Debug")]
    public bool IsDebug { get; set; }
}

public class DatabaseSection
{
    [GenerateIniFileValue("Server")]
    public string Server { get; set; }

    [GenerateIniFileValue("Port")]
    public int Port { get; set; }

    [GenerateIniFileValue("Timeout")]
    public double Timeout { get; set; }
}

Generated Methods

The generator creates the following static methods on the decorated class:

Usage Example

// Reading an INI file
string iniContent = File.ReadAllText("config.ini");
AppConfig config = AppConfig.Read(iniContent);

Console.WriteLine(config.General.ApplicationName); // "MyApp"
Console.WriteLine(config.Database.Port);   // 5432

// Modifying and writing back
config.General.Debug = false;
config.Database.Timeout = 60.0;

string output = AppConfig.Write(config);
File.WriteAllText("config.ini", output);

Output:

[General]
AppName=MyApp
Version=1
Debug=False

[Database]
Server=localhost
Port=5432
Timeout=60

Case-Sensitive Matching:

By default, section and key names are compared case-insensitively (OrdinalIgnoreCase). To use case-sensitive matching:

[GenerateIniFile(StringComparison.Ordinal)]
public partial class StrictConfig
{
    [GenerateIniFileSection("General")]
    public GeneralSection General { get; set; }
}

Nested Sections:

The generator supports nested sections by applying [GenerateIniFileSection] to properties within section types. Nested sections are represented with dotted names (e.g., [Server.Database]), and nesting is supported up to 8 levels deep:

[GenerateIniFile]
public partial class Config
{
    [GenerateIniFileSection]
    public ServerSection Server { get; set; }
}

public class ServerSection
{
    [GenerateIniFileValue]
    public string Host { get; set; }

    [GenerateIniFileSection]
    public DatabaseSection Database { get; set; }
}

public class DatabaseSection
{
    [GenerateIniFileValue]
    public int Port { get; set; }
}

This produces:

[Server]
Host=localhost

[Server.Database]
Port=5432

To use a custom delimiter (e.g., /):

[GenerateIniFile(sectionDelimiter: "/")]
public partial class Config { ... }
// Produces: [Server/Database]

Serializing Comments:

When SerializeComments is set to true, XML documentation <summary> comments on section and value properties are emitted as INI comment lines (prefixed with ; ) in the Write output. The Read method automatically skips these comment lines during deserialization:

[GenerateIniFile(SerializeComments = true)]
public partial class AppConfig
{
    /// <summary>
    /// General application settings
    /// </summary>
    [GenerateIniFileSection]
    public GeneralSection General { get; set; }
}

public class GeneralSection
{
    /// <summary>
    /// The display name of the application
    /// </summary>
    [GenerateIniFileValue]
    public string AppName { get; set; }

    /// <summary>
    /// The current version number
    /// </summary>
    [GenerateIniFileValue]
    public int Version { get; set; }
}

This produces:

; General application settings
[General]
; The display name of the application
AppName=MyApp
; The current version number
Version=1

Enumeration Support:

Regular enums will be serialized as their string name. Enum flags will be serialized as a space-delimited string of individual flag names.

public enum LogLevel { Debug, Info, Warning, Error }

[Flags]
public enum Permissions { None = 0, Read = 1, Write = 2, Execute = 4 }

public class AppSection
{
    [GenerateIniFileValue]
    public LogLevel Level { get; set; }

    [GenerateIniFileValue]
    public Permissions Perms { get; set; }
}

This produces:

[App]
Level=Warning
Perms=Read Write Execute

5. Builder Generator

Generates a fluent builder class for classes, providing With{PropertyName}(value) methods for each public settable property and a Build() method that creates the instance.

Attribute

[GenerateBuilder]

Example

using BB84.SourceGenerators.Attributes;

[GenerateBuilder]
public partial class UserProfile
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string? Email { get; set; }
    public int Age { get; set; }
    public bool IsActive { get; set; }
}

Generated Code

The generator creates a {ClassName}Builder class with:

Usage Example

// Create an instance using the fluent builder
UserProfile profile = new UserProfileBuilder()
    .WithId(1)
    .WithName("John Doe")
    .WithEmail("john@example.com")
    .WithAge(30)
    .WithIsActive(true)
    .Build();

// Only set the properties you need - others use default values
UserProfile minimal = new UserProfileBuilder()
    .WithName("Jane Doe")
    .Build();

// Builders can be reused to create multiple instances
var builder = new UserProfileBuilder()
    .WithName("Template User")
    .WithIsActive(true);

UserProfile first = builder.WithId(1).Build();
UserProfile second = builder.WithId(2).Build();

6. ToString Generator

Generates a ToString() override for classes, returning a formatted string containing the class name and all (or selected) public readable property values in the format ClassName { Prop1 = val1, Prop2 = val2 }.

Attribute

[GenerateToString(params string[] excludeProperties)]

Parameters:

Example

using BB84.SourceGenerators.Attributes;

[GenerateToString]
public partial class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public double Price { get; set; }
    public bool InStock { get; set; }
}

// Exclude sensitive or verbose properties
[GenerateToString("PasswordHash", "InternalNotes")]
public partial class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string PasswordHash { get; set; }
    public string InternalNotes { get; set; }
}

Generated Code

The generator creates a ToString() override on the partial class that:

Usage Example

var product = new Product
{
    Id = 1,
    Name = "Widget",
    Price = 9.99,
    InStock = true
};

Console.WriteLine(product.ToString());
// Output: Product { Id = 1, Name = Widget, Price = 9.99, InStock = True }

var user = new User
{
    Id = 42,
    Name = "John Doe",
    PasswordHash = "abc123hash",
    InternalNotes = "VIP customer"
};

Console.WriteLine(user.ToString());
// Output: User { Id = 42, Name = John Doe }

7. Validator Generator

Generates a Validate() method for classes, scanning properties for data annotation attributes at compile time and emitting direct validation checks. This replaces runtime reflection-based Validator.TryValidateObject() with zero-overhead generated code.

Attribute

[GenerateValidator]

Supported Data Annotations:

Constraints:

Example

using System.ComponentModel.DataAnnotations;
using BB84.SourceGenerators.Attributes;

[GenerateValidator]
public partial class UserRegistration
{
    [Required]
    [StringLength(100, MinimumLength = 2)]
    public string? Name { get; set; }

    [Required]
    [RegularExpression(@"^[^@\s]+@[^@\s]+\.[^@\s]+$")]
    public string? Email { get; set; }

    [Range(18, 120)]
    public int Age { get; set; }

    [Required]
    [MinLength(8)]
    [MaxLength(128)]
    public string? Password { get; set; }

    [Range(1, 10)]
    public List<int>? Skills { get; set; }
}

Generated Code

The generator creates the following methods on the partial class:

Both methods contain direct if-checks for each data annotation rule and support custom error messages via ErrorMessage property.

Usage Example

var registration = new UserRegistration
{
    Name = "J",
    Email = "not-an-email",
    Age = 15,
    Password = "short"
};

Dictionary<string, List<string>> errors = registration.Validate();

if (errors.Count > 0)
{
    foreach (KeyValuePair<string, List<string>> entry in errors)
    {
        Console.WriteLine($"{entry.Key}:");
        foreach (string error in entry.Value)
        {
            Console.WriteLine($"  - {error}");
        }
    }
    // Output:
    // Name:
    //   - The field Name must be a string with a minimum length of 2 and a maximum length of 100.
    // Email:
    //   - The field Email must match the regular expression '^[^@\s]+@[^@\s]+\.[^@\s]+$'.
    // Age:
    //   - The field Age must be between 18 and 120.
    // Password:
    //   - The field Password must be a string or collection with a minimum length of 8.
}
else
{
    Console.WriteLine("Registration is valid!");
}

// Validate a single property
List<string> nameErrors = registration.Validate("Name");
if (nameErrors.Count > 0)
{
    Console.WriteLine($"Name errors: {string.Join(", ", nameErrors)}");
}

// Custom error messages
[GenerateValidator]
public partial class LoginModel
{
    [Required(ErrorMessage = "Username is required.")]
    public string? Username { get; set; }

    [Required(ErrorMessage = "Password cannot be empty.")]
    [MinLength(6, ErrorMessage = "Password must be at least 6 characters.")]
    public string? Password { get; set; }
}

8. Equality Generator

Generates Equals(object), Equals(T), GetHashCode(), operator ==, and operator != for classes, implementing IEquatable<T>. This replaces tedious and error-prone manual equality implementations with zero-overhead generated code.

Attribute

[GenerateEquality(params string[] excludeProperties)]

Parameters:

Example

using BB84.SourceGenerators.Attributes;

[GenerateEquality]
public partial class Product
{
    public int Id { get; set; }
    public string? Name { get; set; }
    public double Price { get; set; }
    public bool InStock { get; set; }
}

// Exclude volatile or non-significant properties
[GenerateEquality("CachedHash", "LastAccessed")]
public partial class User
{
    public int Id { get; set; }
    public string? Name { get; set; }
    public string? CachedHash { get; set; }
    public DateTime LastAccessed { get; set; }
}

Generated Code

The generator creates the following members on the partial class:

Usage Example

var a = new Product { Id = 1, Name = "Widget", Price = 9.99, InStock = true };
var b = new Product { Id = 1, Name = "Widget", Price = 9.99, InStock = true };
var c = new Product { Id = 2, Name = "Gadget", Price = 19.99, InStock = false };

// Typed equality
bool equal = a.Equals(b);    // true
bool different = a.Equals(c); // false

// Operator equality
bool op = a == b;  // true
bool neq = a != c; // true

// Consistent hash codes
bool sameHash = a.GetHashCode() == b.GetHashCode(); // true

// Works with collections that use equality
var set = new HashSet<Product> { a };
bool contains = set.Contains(b); // true

// IEquatable<T> is implemented
IEquatable<Product> equatable = a;

9. Cloneable Generator

Generates Clone() and DeepClone() methods for classes, implementing ICloneable. The Clone() method performs a shallow copy, while DeepClone() recursively deep clones reference-type properties that are also marked with [GenerateCloneable].

Attribute

[GenerateCloneable(params string[] excludeProperties)]

Parameters:

Example

using BB84.SourceGenerators.Attributes;

[GenerateCloneable]
public partial class UserProfile
{
    public int Id { get; set; }
    public string? Name { get; set; }
    public double Score { get; set; }
    public Address? Address { get; set; }
}

[GenerateCloneable]
public partial class Address
{
    public string? Street { get; set; }
    public string? City { get; set; }
}

// Exclude specific properties from cloning
[GenerateCloneable("CacheToken")]
public partial class Session
{
    public int Id { get; set; }
    public string? User { get; set; }
    public string? CacheToken { get; set; }
}

Generated Code

The generator creates the following members on the partial class:

Usage Example

var original = new UserProfile
{
    Id = 1,
    Name = "John Doe",
    Score = 95.5,
    Address = new Address { Street = "123 Main St", City = "Springfield" }
};

// Shallow clone - Address is the same reference
UserProfile shallow = original.Clone();
shallow.Address.City = "Shelbyville";
Console.WriteLine(original.Address.City); // "Shelbyville" (shared reference)

// Deep clone - Address is a new independent instance
UserProfile deep = original.DeepClone();
deep.Address.City = "Capital City";
Console.WriteLine(original.Address.City); // "Shelbyville" (unaffected)

// ICloneable is implemented (delegates to DeepClone)
ICloneable cloneable = original;
object copy = cloneable.Clone();

// Excluded properties are not copied
var session = new Session { Id = 1, User = "admin", CacheToken = "abc123" };
Session clonedSession = session.Clone();
Console.WriteLine(clonedSession.CacheToken); // null

10. Assembly Information Generator

Generates compile-time constant properties for assembly metadata (title, version, company, copyright, etc.), eliminating the need for runtime reflection via Assembly.GetCustomAttribute<T>().

Attribute

[GenerateAssemblyInformation]

Example

using BB84.SourceGenerators.Attributes;

[GenerateAssemblyInformation]
public partial class AppInfo
{ }

Generated Code

The generator creates public const string properties for each standard assembly attribute:

Usage Example

Console.WriteLine(AppInfo.Title);                // "MyApp"
Console.WriteLine(AppInfo.Version);              // "1.0.0.0"
Console.WriteLine(AppInfo.Company);              // "My Company"
Console.WriteLine(AppInfo.Copyright);            // "Copyright © 2025"
Console.WriteLine(AppInfo.InformationalVersion); // "1.0.0+abc123"

11. Singleton Generator

Generates the singleton pattern for classes, providing a static Instance property and a private constructor. Supports thread-safe lazy initialization via Lazy<T> (default) or simple static field initialization. When the class implements an interface, the Instance property is typed as the interface.

Attribute

[GenerateSingleton(bool useLazy = true)]

Parameters:

Constraints:

Example

using BB84.SourceGenerators.Attributes;

// Lazy singleton (default)
[GenerateSingleton]
public partial class MyService { }

// Non-lazy singleton
[GenerateSingleton(useLazy: false)]
public partial class MyCache { }

// Singleton with interface
[GenerateSingleton]
internal partial class MyService : IMyService { }

Generated Code (Lazy, no interface)

public partial class MyService
{
    private static readonly Lazy<MyService> _lazyInstance = new Lazy<MyService>(() => new MyService());

    /// <summary>
    /// Gets the singleton instance of <see cref="MyService"/>.
    /// </summary>
    public static MyService Instance => _lazyInstance.Value;

    private MyService() { }
}

Generated Code (Lazy, with interface)

internal partial class MyService
{
    private static readonly Lazy<MyService> _lazyInstance = new Lazy<MyService>(() => new MyService());

    /// <summary>
    /// Gets the singleton instance of <see cref="MyService"/> as <see cref="IMyService"/>.
    /// </summary>
    public static IMyService Instance => _lazyInstance.Value;

    private MyService() { }
}

Generated Code (Non-lazy, no interface)

public partial class MyCache
{
    /// <summary>
    /// Gets the singleton instance of <see cref="MyCache"/>.
    /// </summary>
    public static MyCache Instance { get; } = new MyCache();

    private MyCache() { }
}

Usage Example

// Access the singleton instance
MyService service = MyService.Instance;

// With interface typing
IMyService service = MyService.Instance;

// Thread-safe - always returns the same instance
MyService a = MyService.Instance;
MyService b = MyService.Instance;
// a and b are the same reference

12. Decorator Generator

Generates a decorator class that wraps an inner instance, delegates all interface members to it, and exposes them as virtual methods and properties for selective overriding. This replaces runtime proxy generation (e.g., DispatchProxy, Castle.Core DynamicProxy) with zero-overhead compile-time code.

Attribute

[GenerateDecorator]

Example

using BB84.SourceGenerators.Attributes;

public interface IMyService
{
    string? Name { get; set; }
    int Count { get; }
    string GetMessage(string input);
    void DoWork();
}

[GenerateDecorator]
public partial class MyServiceDecorator : IMyService
{ }

Generated Code

The generator creates the following members on the partial class:

Usage Example

// Basic delegation - all calls forwarded to inner instance
var inner = new MyService();
var decorator = new MyServiceDecorator(inner);

decorator.DoWork();           // delegates to inner.DoWork()
string msg = decorator.GetMessage("Hi"); // delegates to inner.GetMessage("Hi")

// Override specific behavior by inheriting from the decorator
public class LoggingDecorator(IMyService inner) : MyServiceDecorator(inner)
{
    public override string GetMessage(string input)
    {
        Console.WriteLine($"GetMessage called with: {input}");
        return base.GetMessage(input);
    }

    public override string? Name
    {
        get => base.Name?.ToUpperInvariant();
        set => base.Name = value;
    }
}

// Multiple interfaces are supported
public interface ICalculator
{
    int Calculate(int a, int b);
}

[GenerateDecorator]
public partial class MultiDecorator : IMyService, ICalculator
{ }

// In your DI container
services.AddSingleton<IMyService>(sp =>
    new LoggingDecorator(sp.GetRequiredService<MyService>()));

13. Factory Generator

Generates a factory class that discovers all concrete implementations of a target interface at compile time and emits a Create(string key) method that maps keys to concrete types. This eliminates runtime assembly scanning and manual factory maintenance entirely.

Attributes

[GenerateFactory(Type interfaceType)]
[GenerateFactoryKey(string key)]

Parameters:

Constraints:

Example

using BB84.SourceGenerators.Attributes;

public interface IAnimal
{
    string Speak();
}

public class Dog : IAnimal
{
    public string Speak() => "Woof!";
}

public class Cat : IAnimal
{
    public string Speak() => "Meow!";
}

[GenerateFactory(typeof(IAnimal))]
public partial class AnimalFactory
{ }

Generated Code

The generator creates the following static methods on the partial class:

Usage Example

// Create instances by type name (default key)
IAnimal dog = AnimalFactory.Create("Dog");
IAnimal cat = AnimalFactory.Create("Cat");

Console.WriteLine(dog.Speak()); // "Woof!"
Console.WriteLine(cat.Speak()); // "Meow!"

// Unknown keys throw ArgumentException
try
{
    AnimalFactory.Create("Fish");
}
catch (ArgumentException ex)
{
    Console.WriteLine(ex.Message); // "No implementation registered for key 'Fish'."
}

// Enumerate all registered keys
foreach (string key in AnimalFactory.GetKeys())
{
    Console.WriteLine(key); // "Dog", "Cat"
}

// Use custom keys with [GenerateFactoryKey]
public interface IVehicle
{
    string Type { get; }
}

[GenerateFactoryKey("sedan")]
public class Car : IVehicle
{
    public string Type => "Car";
}

[GenerateFactoryKey("pickup")]
public class Truck : IVehicle
{
    public string Type => "Truck";
}

[GenerateFactory(typeof(IVehicle))]
public partial class VehicleFactory
{ }

// Create using custom keys
IVehicle vehicle = VehicleFactory.Create("sedan");
Console.WriteLine(vehicle.Type); // "Car"

14. Disposable Generator

Generates the complete dispose pattern for classes, implementing IDisposable and optionally IAsyncDisposable. Fields marked with [DisposeResource] are automatically disposed with configurable ordering.

Attributes

[GenerateDisposable(bool generateFinalizer = false, bool async = false)]
[DisposeResource(int order = 0)]

Parameters:

Constraints:

Example

using BB84.SourceGenerators.Attributes;

[GenerateDisposable]
public partial class ConnectionManager
{
    [DisposeResource]
    private Stream _stream;

    [DisposeResource(order: 1)]
    private DbConnection _connection;

    private string _name; // not disposed (no attribute)

    public ConnectionManager(Stream stream, DbConnection connection)
    {
        _stream = stream;
        _connection = connection;
    }
}

Generated Code

The generator creates:

Usage Example

// Basic usage
var manager = new ConnectionManager(stream, connection);
// ... use resources ...
manager.Dispose(); // _connection disposed first (order 1), then _stream (order 0)

// With finalizer for unmanaged resources
[GenerateDisposable(generateFinalizer: true)]
public partial class NativeResourceWrapper
{
    [DisposeResource]
    private SafeHandle _handle;
}

// With async disposal
[GenerateDisposable(async: true)]
public partial class AsyncService
{
    [DisposeResource]
    private HttpClient _client;

    [DisposeResource(order: 1)]
    private DbConnection _connection;
}

await using var service = new AsyncService(client, connection);

// Sealed classes work correctly (private methods instead of protected virtual)
[GenerateDisposable]
public sealed partial class SealedResource
{
    [DisposeResource]
    private Stream _stream;
}

// Ordered disposal - dispose writer before underlying stream
[GenerateDisposable]
public partial class FileProcessor
{
    [DisposeResource(order: 2)]
    private Stream _stream;

    [DisposeResource(order: 1)]
    private StreamWriter _writer;
}

Requirements

Performance Benefits

Enum Extensions

The generated enum extension methods provide significant performance improvements over reflection-based Enum methods:

Notification Properties

INI File Serialization

Builder Pattern

ToString Generation

Validation

Equality

Cloneable

Assembly Information

Singleton

Decorator

Factory

Disposable

How It Works

Source generators run during compilation and generate additional C# source files that are compiled alongside your code. This means:

Contributing

Contributions are welcome! If you have an idea for a new feature, improvement, or bug fix, please follow these steps:

  1. Have a look at the Issues to see if your idea has already been discussed.
  2. If you want to work on an existing issue, please comment on the issue to let others know you’re working on it.
  3. Fork the repository and create a new branch for your contribution.
  4. Make your changes and commit them with clear and descriptive messages.
  5. Push your changes to your forked repository and submit a pull request to the main repository.

Code of Conduct

We expect all contributors to adhere to the Code of Conduct.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Author

Robert Peter Meyer (BoBoBaSs84)

Changelog

See releases for version history and changelog.