{"id":14966907,"url":"https://github.com/reactiveui/splat.di.sourcegenerator","last_synced_at":"2026-01-21T10:00:40.777Z","repository":{"id":39572767,"uuid":"379091414","full_name":"reactiveui/Splat.DI.SourceGenerator","owner":"reactiveui","description":null,"archived":false,"fork":false,"pushed_at":"2025-06-23T14:03:48.000Z","size":322,"stargazers_count":34,"open_issues_count":14,"forks_count":5,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-07-18T03:45:44.620Z","etag":null,"topics":["c-sharp","dependency-injection"],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/reactiveui.png","metadata":{"funding":{"github":["reactivemarbles"]},"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-06-21T23:51:02.000Z","updated_at":"2025-04-08T09:35:36.000Z","dependencies_parsed_at":"2023-12-19T04:22:52.689Z","dependency_job_id":"9168c375-db80-4b26-a815-fe58a88a013e","html_url":"https://github.com/reactiveui/Splat.DI.SourceGenerator","commit_stats":{"total_commits":151,"total_committers":7,"mean_commits":"21.571428571428573","dds":0.5033112582781457,"last_synced_commit":"38201986c97bc9253233bf63ed4b7d08038e2875"},"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/reactiveui/Splat.DI.SourceGenerator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactiveui%2FSplat.DI.SourceGenerator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactiveui%2FSplat.DI.SourceGenerator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactiveui%2FSplat.DI.SourceGenerator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactiveui%2FSplat.DI.SourceGenerator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/reactiveui","download_url":"https://codeload.github.com/reactiveui/Splat.DI.SourceGenerator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactiveui%2FSplat.DI.SourceGenerator/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266236771,"owners_count":23897248,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c-sharp","dependency-injection"],"created_at":"2024-09-24T13:37:08.037Z","updated_at":"2026-01-21T10:00:40.771Z","avatar_url":"https://github.com/reactiveui.png","language":"C#","funding_links":["https://github.com/sponsors/reactivemarbles"],"categories":[],"sub_categories":[],"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)\n[![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)\n[![NuGet](https://img.shields.io/nuget/v/Splat.DependencyInjection.SourceGenerator.svg)](https://www.nuget.org/packages/Splat.DependencyInjection.SourceGenerator/)\n[![NuGet Downloads](https://img.shields.io/nuget/dt/Splat.DependencyInjection.SourceGenerator.svg)](https://www.nuget.org/packages/Splat.DependencyInjection.SourceGenerator/)\n\u003cbr\u003e\n\u003ca href=\"https://reactiveui.net/slack\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/chat-slack-blue.svg\"\u003e\n\u003c/a\u003e\n\n# Splat Dependency Injection Source Generator\n\nA 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.\n\n## What does it do?\n\nThis 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.\n\nKey features:\n- Zero reflection - All registrations generated at compile-time\n- Native AOT compatible - Works with trimming and AOT compilation\n- Built-in analyzers - Real-time diagnostics and automatic code fixes\n- Constructor injection - Automatic dependency resolution\n- Property injection - Attribute-based property initialization\n- Lazy singletons - Thread-safe lazy initialization with configurable modes\n- Contract support - Named registrations for multiple implementations\n- Incremental compilation - Fast builds that only regenerate when needed\n\n## How do I install?\n\n[Always Be NuGetting](https://nuget.org/packages/Splat.DependencyInjection.SourceGenerator/). Package contains:\n\n| Package                          | NuGet                            |\n| -------------------------------- | -------------------------------- |\n| [Splat.DependencyInjection.SourceGenerator][Core] | [![CoreBadge]][Core] |\n\n[Core]: https://www.nuget.org/packages/Splat.DependencyInjection.SourceGenerator/\n[CoreBadge]: https://img.shields.io/nuget/v/Splat.DependencyInjection.SourceGenerator.svg\n\n### Requirements\n\n- .NET SDK: Any version supporting C# 7.3 or later\n- Target Frameworks: .NET Framework 4.6.2+, .NET 8+, .NET 9+, .NET 10+\n- Splat: Version 19.1.1 or later (supports modern generic-first resolvers)\n\n### Installation\n\nAdd the package to your project:\n\n```xml\n\u003cPackageReference Include=\"Splat.DependencyInjection.SourceGenerator\" Version=\"{latest version}\" PrivateAssets=\"all\" /\u003e\n```\n\nNote: 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.\n\n## How to Use\n\n### Register Your Dependencies\n\nUse the `SplatRegistrations` static class to register services. The source generator will detect these calls and generate the implementation at compile-time.\n\n**Transient Registration (New Instance Each Time)**\n\n```csharp\nusing static Splat.SplatRegistrations;\n\n// Register with interface and implementation\nRegister\u003cIToaster, Toaster\u003e();\nRegister\u003cIMessageService, MessageService\u003e();\n\n// Register concrete type only (when no interface)\nRegister\u003cDatabaseContext\u003e();\n```\n\n**Lazy Singleton Registration (Single Lazy Instance)**\n\n```csharp\n// Basic lazy singleton\nRegisterLazySingleton\u003cIDatabase, SqliteDatabase\u003e();\n\n// With thread safety mode\nRegisterLazySingleton\u003cICache, MemoryCache\u003e(LazyThreadSafetyMode.PublicationOnly);\n```\n\nThread safety modes:\n- `LazyThreadSafetyMode.ExecutionAndPublication` (default) - Full thread safety with locks\n- `LazyThreadSafetyMode.PublicationOnly` - Multiple threads may initialize, first wins\n- `LazyThreadSafetyMode.None` - No thread safety (single-threaded scenarios only)\n\n**Constant Registration (Pre-Created Instance)**\n\n```csharp\n// Register an existing instance\nvar config = new Configuration { ApiUrl = \"https://api.example.com\" };\nRegisterConstant\u003cIConfiguration\u003e(config);\n```\n\n**Named Contracts (Multiple Implementations)**\n\n```csharp\n// Register multiple implementations with different contracts\nRegister\u003cILogger, FileLogger\u003e(\"file\");\nRegister\u003cILogger, ConsoleLogger\u003e(\"console\");\nRegister\u003cILogger, CloudLogger\u003e(\"cloud\");\n\n// Retrieve by contract\nvar fileLogger = resolver.GetService\u003cILogger\u003e(\"file\");\n```\n\n### Initialize the Container\n\nCall `SetupIOC()` once during application startup in each assembly that uses `SplatRegistrations`:\n\n```csharp\nusing Splat;\nusing static Splat.SplatRegistrations;\n\n// In your application entry point\npublic class App\n{\n    public void ConfigureServices()\n    {\n        // Register all dependencies\n        Register\u003cIUserService, UserService\u003e();\n        Register\u003cIAuthService, AuthService\u003e();\n        RegisterLazySingleton\u003cIDatabase, AppDatabase\u003e();\n\n        // Initialize the container (generates and executes registrations)\n        SetupIOC();\n    }\n}\n```\n\nFor unit tests, pass a custom resolver:\n\n```csharp\n[Test]\npublic void TestDependencies()\n{\n    var resolver = new ModernDependencyResolver();\n    SetupIOC(resolver); // Use test-specific resolver\n\n    var service = resolver.GetService\u003cIUserService\u003e();\n    Assert.NotNull(service);\n}\n```\n\n### Constructor Injection\n\nThe source generator automatically resolves constructor parameters.\n\n**Single Constructor**\n\n```csharp\npublic class UserService : IUserService\n{\n    private readonly IDatabase _database;\n    private readonly ILogger _logger;\n\n    // Automatically detected - no attribute needed\n    public UserService(IDatabase database, ILogger logger)\n    {\n        _database = database;\n        _logger = logger;\n    }\n}\n```\n\n**Multiple Constructors**\n\nUse `[DependencyInjectionConstructor]` to specify which constructor to use:\n\n```csharp\nusing static Splat.SplatRegistrations;\n\npublic class AuthService : IAuthService\n{\n    private readonly IDatabase _database;\n    private readonly ILogger _logger;\n\n    // Empty constructor for testing\n    public AuthService()\n    {\n        _database = new InMemoryDatabase();\n        _logger = new NullLogger();\n    }\n\n    // Production constructor - marked for DI\n    [DependencyInjectionConstructor]\n    public AuthService(IDatabase database, ILogger logger)\n    {\n        _database = database;\n        _logger = logger;\n    }\n}\n```\n\nIf you forget the attribute with multiple constructors, the analyzer will warn you and offer a code fix to add it automatically.\n\n**Lazy Dependencies**\n\nInject `Lazy\u003cT\u003e` for on-demand initialization:\n\n```csharp\npublic class ExpensiveService\n{\n    private readonly Lazy\u003cIDatabase\u003e _database;\n\n    public ExpensiveService(Lazy\u003cIDatabase\u003e database)\n    {\n        _database = database; // Not initialized yet\n    }\n\n    public void DoWork()\n    {\n        // Database initialized only when first accessed\n        _database.Value.ExecuteQuery(\"...\");\n    }\n}\n\n// Register the dependency as a lazy singleton\nRegisterLazySingleton\u003cIDatabase, AppDatabase\u003e();\nRegister\u003cIExpensiveService, ExpensiveService\u003e();\n```\n\n### Property Injection\n\nMark properties with `[DependencyInjectionProperty]` for initialization after construction.\n\n```csharp\nusing static Splat.SplatRegistrations;\n\npublic class ViewModelBase\n{\n    // Property injection - must have public or internal setter\n    [DependencyInjectionProperty]\n    public INavigationService Navigation { get; set; }\n\n    [DependencyInjectionProperty]\n    public ILogger Logger { get; internal set; } // Internal setters supported\n}\n```\n\nThe analyzer will:\n- Warn if property doesn't have a public/internal setter\n- Offer code fix to change `private set` to `public set` or `internal set`\n- Offer code fix to add missing setter to read-only properties\n\n### Complete Example\n\n```csharp\nusing Splat;\nusing static Splat.SplatRegistrations;\n\n// Models\npublic interface IDatabase { }\npublic interface ILogger { }\npublic interface IUserService { }\n\npublic class SqliteDatabase : IDatabase { }\npublic class FileLogger : ILogger { }\n\npublic class UserService : IUserService\n{\n    private readonly IDatabase _database;\n\n    // Constructor injection\n    public UserService(IDatabase database)\n    {\n        _database = database;\n    }\n\n    // Property injection\n    [DependencyInjectionProperty]\n    public ILogger Logger { get; set; }\n}\n\n// Application startup\npublic class Program\n{\n    public static void Main()\n    {\n        // Register dependencies\n        RegisterLazySingleton\u003cIDatabase, SqliteDatabase\u003e();\n        Register\u003cILogger, FileLogger\u003e();\n        Register\u003cIUserService, UserService\u003e();\n\n        // Initialize container\n        SetupIOC();\n\n        // Resolve services\n        var userService = Locator.Current.GetService\u003cIUserService\u003e();\n    }\n}\n```\n\n## Built-in Analyzers and Code Fixes\n\nThe package includes intelligent analyzers that provide real-time feedback:\n\n| Diagnostic ID | Severity | Description | Code Fix |\n|--------------|----------|-------------|----------|\n| SPLATDI001 | Warning | Multiple constructors without `[DependencyInjectionConstructor]` attribute | Adds attribute to selected constructor |\n| SPLATDI002 | Error | Property with `[DependencyInjectionProperty]` lacks accessible setter | Changes setter to `public` or `internal` |\n| SPLATDI003 | Error | Multiple constructors marked with `[DependencyInjectionConstructor]` | Manual fix required |\n| SPLATDI004 | Error | Constructor marked with `[DependencyInjectionConstructor]` is not accessible | Changes to `public` or `internal` |\n\nThe analyzer detects issues in real-time and offers automatic fixes via Quick Actions (Ctrl+. or Cmd+.).\n\n## How It Works\n\nThe source generator follows a four-step process:\n\n1. Compile-Time Detection - Scans for `SplatRegistrations.Register()` calls during compilation\n2. Metadata Extraction - Analyzes constructor parameters and property injection requirements\n3. Code Generation - Generates optimized registration code with no reflection\n4. Incremental Builds - Only regenerates when relevant code changes\n\nGenerated code example:\n\n```csharp\n// Generated by Splat.DependencyInjection.SourceGenerator\nstatic partial void SetupIOCInternal(IDependencyResolver resolver)\n{\n    // Transient registration\n    resolver.Register\u003cIUserService\u003e(() =\u003e new UserService(\n        (IDatabase)resolver.GetService(typeof(IDatabase)),\n        (ILogger)resolver.GetService(typeof(ILogger))\n    ) {\n        Navigation = (INavigationService)resolver.GetService(typeof(INavigationService))\n    });\n\n    // Lazy singleton registration\n    {\n        var lazy = new Lazy\u003cIDatabase\u003e(() =\u003e new SqliteDatabase(),\n            LazyThreadSafetyMode.ExecutionAndPublication);\n        resolver.Register\u003cLazy\u003cIDatabase\u003e\u003e(() =\u003e lazy);\n        resolver.Register\u003cIDatabase\u003e(() =\u003e lazy.Value);\n    }\n}\n```\n\n## Performance Benefits\n\nCompared to reflection-based DI:\n- Approximately 100x faster registration execution (no runtime reflection)\n- Approximately 10-100x faster incremental builds (only processes changed files)\n- Full AOT support (works with Native AOT and trimming)\n- Zero runtime overhead (all work done at compile-time)\n\n## Troubleshooting\n\n**Generator doesn't seem to run?**\n\nEnsure you called `SetupIOC()` in your startup code. The generator only produces code for assemblies that use `SplatRegistrations`.\n\n**\"Multiple constructors\" warning?**\n\nAdd `[DependencyInjectionConstructor]` to the constructor you want used. Use the Quick Fix to add automatically.\n\n**Property injection not working?**\n\nEnsure the property has `[DependencyInjectionProperty]` and a `public` or `internal` setter. The analyzer will warn if the setter is missing or inaccessible.\n\n**Lazy dependencies not resolving?**\n\nMake sure you registered the dependency with `RegisterLazySingleton`, not `Register`. Only lazy singletons can be injected as `Lazy\u003cT\u003e`.\n\n## Migration from Version 1.x to 2.x\n\nVersion 2.1.1 includes breaking changes:\n\n- Requires Splat 19.1.1 or later for generic-first resolver support\n- Migrated from legacy `ISourceGenerator` to modern `IIncrementalGenerator`\n- Updated to Roslyn 4.14.0\n- Removed support for .NET Standard 2.0 and .NET 6\n- Minimum supported frameworks: .NET Framework 4.6.2+, .NET 8+, .NET 9+, .NET 10+\n\nNew features in 2.1.1:\n- 10-100x faster incremental builds (only processes changed files)\n- Cache-friendly pipeline eliminates unnecessary recompilation\n- Built-in analyzers with real-time diagnostics and automatic code fixes\n- Full Native AOT and trimming support with generic-first API\n\n## Support\n\nIf you have questions or need help:\n\n- Check existing [GitHub Issues](https://github.com/reactiveui/Splat.DI.SourceGenerator/issues)\n- Ask on [Stack Overflow](https://stackoverflow.com/questions/tagged/splat) with the `splat` tag\n- Join our [Slack community](https://reactiveui.net/slack)\n\nPlease do not open GitHub issues for general support questions.\n\n## Contribute\n\nWe welcome contributions! Here's how you can help:\n\n1. Report Issues: Found a bug? [Open an issue](https://github.com/reactiveui/Splat.DI.SourceGenerator/issues/new)\n2. Submit PRs: Improvements are always welcome\n3. Documentation: Help improve our examples and docs\n4. Testing: Add test cases for edge scenarios\n\nSee our [contribution guidelines](CONTRIBUTING.md) for details.\n\n## Sponsorship\n\nThe 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:\n\n[Become a sponsor](https://github.com/sponsors/reactivemarbles)\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freactiveui%2Fsplat.di.sourcegenerator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freactiveui%2Fsplat.di.sourcegenerator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freactiveui%2Fsplat.di.sourcegenerator/lists"}