# Splat.DI.SourceGenerator **Repository Path**: mirrors_reactiveui/Splat.DI.SourceGenerator ## Basic Information - **Project Name**: Splat.DI.SourceGenerator - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-01-28 - **Last Updated**: 2026-02-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README [![Build](https://github.com/reactiveui/Splat.DI.SourceGenerator/actions/workflows/ci-build.yml/badge.svg)](https://github.com/reactiveui/Splat.DI.SourceGenerator/actions/workflows/ci-build.yml) [![Code Coverage](https://codecov.io/gh/reactiveui/Splat.DI.SourceGenerator/branch/main/graph/badge.svg?token=dmQeHH4Us8)](https://codecov.io/gh/reactiveui/Splat.DI.SourceGenerator) [![NuGet](https://img.shields.io/nuget/v/Splat.DependencyInjection.SourceGenerator.svg)](https://www.nuget.org/packages/Splat.DependencyInjection.SourceGenerator/) [![NuGet Downloads](https://img.shields.io/nuget/dt/Splat.DependencyInjection.SourceGenerator.svg)](https://www.nuget.org/packages/Splat.DependencyInjection.SourceGenerator/)
# Splat Dependency Injection Source Generator A high-performance C# source generator that produces compile-time dependency injection registrations for [Splat](https://github.com/reactiveui/splat). Eliminates runtime reflection, provides full native AOT support, and includes intelligent analyzers with automatic code fixes. ## What does it do? This source generator produces dependency injection registrations for Splat at compile-time based on your constructor and property injection requirements. It uses an incremental source generator to provide fast builds with zero runtime reflection overhead. Key features: - Zero reflection - All registrations generated at compile-time - Native AOT compatible - Works with trimming and AOT compilation - Built-in analyzers - Real-time diagnostics and automatic code fixes - Constructor injection - Automatic dependency resolution - Property injection - Attribute-based property initialization - Lazy singletons - Thread-safe lazy initialization with configurable modes - Contract support - Named registrations for multiple implementations - Incremental compilation - Fast builds that only regenerate when needed ## How do I install? [Always Be NuGetting](https://nuget.org/packages/Splat.DependencyInjection.SourceGenerator/). Package contains: | Package | NuGet | | -------------------------------- | -------------------------------- | | [Splat.DependencyInjection.SourceGenerator][Core] | [![CoreBadge]][Core] | [Core]: https://www.nuget.org/packages/Splat.DependencyInjection.SourceGenerator/ [CoreBadge]: https://img.shields.io/nuget/v/Splat.DependencyInjection.SourceGenerator.svg ### Requirements - .NET SDK: Any version supporting C# 7.3 or later - Target Frameworks: .NET Framework 4.6.2+, .NET 8+, .NET 9+, .NET 10+ - Splat: Version 19.1.1 or later (supports modern generic-first resolvers) ### Installation Add the package to your project: ```xml ``` Note: The `PrivateAssets="all"` attribute prevents the source generator from being transitively referenced by projects that depend on yours. This is the recommended configuration for source generators. ## How to Use ### Register Your Dependencies Use the `SplatRegistrations` static class to register services. The source generator will detect these calls and generate the implementation at compile-time. **Transient Registration (New Instance Each Time)** ```csharp using static Splat.SplatRegistrations; // Register with interface and implementation Register(); Register(); // Register concrete type only (when no interface) Register(); ``` **Lazy Singleton Registration (Single Lazy Instance)** ```csharp // Basic lazy singleton RegisterLazySingleton(); // With thread safety mode RegisterLazySingleton(LazyThreadSafetyMode.PublicationOnly); ``` Thread safety modes: - `LazyThreadSafetyMode.ExecutionAndPublication` (default) - Full thread safety with locks - `LazyThreadSafetyMode.PublicationOnly` - Multiple threads may initialize, first wins - `LazyThreadSafetyMode.None` - No thread safety (single-threaded scenarios only) **Constant Registration (Pre-Created Instance)** ```csharp // Register an existing instance var config = new Configuration { ApiUrl = "https://api.example.com" }; RegisterConstant(config); ``` **Named Contracts (Multiple Implementations)** ```csharp // Register multiple implementations with different contracts Register("file"); Register("console"); Register("cloud"); // Retrieve by contract var fileLogger = resolver.GetService("file"); ``` ### Initialize the Container Call `SetupIOC()` once during application startup in each assembly that uses `SplatRegistrations`: ```csharp using Splat; using static Splat.SplatRegistrations; // In your application entry point public class App { public void ConfigureServices() { // Register all dependencies Register(); Register(); RegisterLazySingleton(); // Initialize the container (generates and executes registrations) SetupIOC(); } } ``` For unit tests, pass a custom resolver: ```csharp [Test] public void TestDependencies() { var resolver = new ModernDependencyResolver(); SetupIOC(resolver); // Use test-specific resolver var service = resolver.GetService(); Assert.NotNull(service); } ``` ### Constructor Injection The source generator automatically resolves constructor parameters. **Single Constructor** ```csharp public class UserService : IUserService { private readonly IDatabase _database; private readonly ILogger _logger; // Automatically detected - no attribute needed public UserService(IDatabase database, ILogger logger) { _database = database; _logger = logger; } } ``` **Multiple Constructors** Use `[DependencyInjectionConstructor]` to specify which constructor to use: ```csharp using static Splat.SplatRegistrations; public class AuthService : IAuthService { private readonly IDatabase _database; private readonly ILogger _logger; // Empty constructor for testing public AuthService() { _database = new InMemoryDatabase(); _logger = new NullLogger(); } // Production constructor - marked for DI [DependencyInjectionConstructor] public AuthService(IDatabase database, ILogger logger) { _database = database; _logger = logger; } } ``` If you forget the attribute with multiple constructors, the analyzer will warn you and offer a code fix to add it automatically. **Lazy Dependencies** Inject `Lazy` for on-demand initialization: ```csharp public class ExpensiveService { private readonly Lazy _database; public ExpensiveService(Lazy database) { _database = database; // Not initialized yet } public void DoWork() { // Database initialized only when first accessed _database.Value.ExecuteQuery("..."); } } // Register the dependency as a lazy singleton RegisterLazySingleton(); Register(); ``` ### Property Injection Mark properties with `[DependencyInjectionProperty]` for initialization after construction. ```csharp using static Splat.SplatRegistrations; public class ViewModelBase { // Property injection - must have public or internal setter [DependencyInjectionProperty] public INavigationService Navigation { get; set; } [DependencyInjectionProperty] public ILogger Logger { get; internal set; } // Internal setters supported } ``` The analyzer will: - Warn if property doesn't have a public/internal setter - Offer code fix to change `private set` to `public set` or `internal set` - Offer code fix to add missing setter to read-only properties ### Complete Example ```csharp using Splat; using static Splat.SplatRegistrations; // Models public interface IDatabase { } public interface ILogger { } public interface IUserService { } public class SqliteDatabase : IDatabase { } public class FileLogger : ILogger { } public class UserService : IUserService { private readonly IDatabase _database; // Constructor injection public UserService(IDatabase database) { _database = database; } // Property injection [DependencyInjectionProperty] public ILogger Logger { get; set; } } // Application startup public class Program { public static void Main() { // Register dependencies RegisterLazySingleton(); Register(); Register(); // Initialize container SetupIOC(); // Resolve services var userService = Locator.Current.GetService(); } } ``` ## Built-in Analyzers and Code Fixes The package includes intelligent analyzers that provide real-time feedback: | Diagnostic ID | Severity | Description | Code Fix | |--------------|----------|-------------|----------| | SPLATDI001 | Warning | Multiple constructors without `[DependencyInjectionConstructor]` attribute | Adds attribute to selected constructor | | SPLATDI002 | Error | Property with `[DependencyInjectionProperty]` lacks accessible setter | Changes setter to `public` or `internal` | | SPLATDI003 | Error | Multiple constructors marked with `[DependencyInjectionConstructor]` | Manual fix required | | SPLATDI004 | Error | Constructor marked with `[DependencyInjectionConstructor]` is not accessible | Changes to `public` or `internal` | The analyzer detects issues in real-time and offers automatic fixes via Quick Actions (Ctrl+. or Cmd+.). ## How It Works The source generator follows a four-step process: 1. Compile-Time Detection - Scans for `SplatRegistrations.Register()` calls during compilation 2. Metadata Extraction - Analyzes constructor parameters and property injection requirements 3. Code Generation - Generates optimized registration code with no reflection 4. Incremental Builds - Only regenerates when relevant code changes Generated code example: ```csharp // Generated by Splat.DependencyInjection.SourceGenerator static partial void SetupIOCInternal(IDependencyResolver resolver) { // Transient registration resolver.Register(() => new UserService( (IDatabase)resolver.GetService(typeof(IDatabase)), (ILogger)resolver.GetService(typeof(ILogger)) ) { Navigation = (INavigationService)resolver.GetService(typeof(INavigationService)) }); // Lazy singleton registration { var lazy = new Lazy(() => new SqliteDatabase(), LazyThreadSafetyMode.ExecutionAndPublication); resolver.Register>(() => lazy); resolver.Register(() => lazy.Value); } } ``` ## Performance Benefits Compared to reflection-based DI: - Approximately 100x faster registration execution (no runtime reflection) - Approximately 10-100x faster incremental builds (only processes changed files) - Full AOT support (works with Native AOT and trimming) - Zero runtime overhead (all work done at compile-time) ## Troubleshooting **Generator doesn't seem to run?** Ensure you called `SetupIOC()` in your startup code. The generator only produces code for assemblies that use `SplatRegistrations`. **"Multiple constructors" warning?** Add `[DependencyInjectionConstructor]` to the constructor you want used. Use the Quick Fix to add automatically. **Property injection not working?** Ensure the property has `[DependencyInjectionProperty]` and a `public` or `internal` setter. The analyzer will warn if the setter is missing or inaccessible. **Lazy dependencies not resolving?** Make sure you registered the dependency with `RegisterLazySingleton`, not `Register`. Only lazy singletons can be injected as `Lazy`. ## Migration from Version 1.x to 2.x Version 2.1.1 includes breaking changes: - Requires Splat 19.1.1 or later for generic-first resolver support - Migrated from legacy `ISourceGenerator` to modern `IIncrementalGenerator` - Updated to Roslyn 4.14.0 - Removed support for .NET Standard 2.0 and .NET 6 - Minimum supported frameworks: .NET Framework 4.6.2+, .NET 8+, .NET 9+, .NET 10+ New features in 2.1.1: - 10-100x faster incremental builds (only processes changed files) - Cache-friendly pipeline eliminates unnecessary recompilation - Built-in analyzers with real-time diagnostics and automatic code fixes - Full Native AOT and trimming support with generic-first API ## Support If you have questions or need help: - Check existing [GitHub Issues](https://github.com/reactiveui/Splat.DI.SourceGenerator/issues) - Ask on [Stack Overflow](https://stackoverflow.com/questions/tagged/splat) with the `splat` tag - Join our [Slack community](https://reactiveui.net/slack) Please do not open GitHub issues for general support questions. ## Contribute We welcome contributions! Here's how you can help: 1. Report Issues: Found a bug? [Open an issue](https://github.com/reactiveui/Splat.DI.SourceGenerator/issues/new) 2. Submit PRs: Improvements are always welcome 3. Documentation: Help improve our examples and docs 4. Testing: Add test cases for edge scenarios See our [contribution guidelines](CONTRIBUTING.md) for details. ## Sponsorship The core team members and contributors work on this project in their free time. If Splat.DI.SourceGenerator increases your productivity, please consider supporting the project: [Become a sponsor](https://github.com/sponsors/reactivemarbles) ## License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.