A lightweight dependency injection library for C# that combines simple DI container functionality with powerful source generation for content management.
- Attribute-based registration - Mark classes with
[Singleton],[Scoped], or[Transient] - Automatic service discovery - No manual registration required
- Constructor injection - Automatic dependency resolution
- Scope management - Built-in scoped service lifetime management
- Automatic enum generation - Creates enums from your content collections
- Type-safe access - Generated helper methods for accessing content by enum or index
- Performance optimized - Uses
NamedComparer<T>for fast dictionary lookups - Roslyn analyzers - Enforces best practices and catches common mistakes
dotnet add package SimpleInjectionMark your classes with lifetime attributes:
[Singleton]publicclassDatabaseService{publicvoidConnect()=>Console.WriteLine("Connected to database");}[Scoped]publicclassUserService{privatereadonlyDatabaseService_database;publicUserService(DatabaseServicedatabase){_database=database;}publicvoidGetUser()=>_database.Connect();}Initialize and use the host:
varhost=Host.Initialize();// Get singleton services directlyvardbService=host.Get<DatabaseService>();// Create scopes for scoped servicesusingvarscope=host.CreateScope();varuserService=scope.Get<UserService>();Define your content classes:
// Your content item must implement INamedpublicrecordMaterial(stringName,stringColor,intDurability):INamed;// Your content collection must implement IContent<T>[Singleton]publicpartialclassMaterials:IContent<Material>{publicMaterial[]All{get;}=[new("Steel","Gray",100),new("Wood","Brown",50),new("Gold","Yellow",25)];}The source generator automatically creates:
// Generated enumpublicenumMaterialsType{Steel,Wood,Gold}// Generated helper methodspublicpartialclassMaterials{publicMaterialGet(MaterialsTypetype)=>All[(int)type];publicMaterialthis[MaterialsTypetype]=>All[(int)type];publicMaterialGetById(intid)=>All[id];publicMaterialSteel=>All[0];publicMaterialWood=>All[1];publicMaterialGold=>All[2];}Use the generated code:
varmaterials=host.Get<Materials>();// Type-safe access using enumsvarsteel=materials[MaterialsType.Steel];varwood=materials.Get(MaterialsType.Wood);// Direct property accessvargold=materials.Gold;// Index-based accessvarfirstMaterial=materials.GetById(0);The library includes NamedComparer<T> for efficient dictionary operations with INamed keys:
// Use ToNamedDictionary extension methodvarmaterialDict=materials.All.ToNamedDictionary(m =>m.Durability);// Or explicitly specify the comparervardict=newDictionary<Material,int>(newNamedComparer<Material>());For hierarchical content organization:
publicclassWeaponStats:ISubContent<Material,int>{publicDictionary<Material,int>ByKey{get;}publicintthis[Materialmaterial]=>ByKey[material];}The package includes analyzers that help you:
- NC001: Ensures
Dictionary<TKey, TValue>usesNamedComparer<T>forINamedkeys - TND001: Suggests using
ToNamedDictionary()instead ofToDictionary()forINamedkeys
- .NET 8.0 or .NET 9.0
- C# with nullable reference types enabled (recommended)
- Service Discovery: The host scans all loaded assemblies for classes marked with lifetime attributes
- Dependency Resolution: Constructor parameters are automatically resolved from registered services
- Source Generation: The generator scans for classes implementing
IContent<T>and generates enums and helper methods - Code Analysis: Roslyn analyzers ensure best practices for dictionary usage with named keys
- Use
[Singleton]for stateless services and shared resources - Use
[Scoped]for services that should be unique per operation/request - Use
[Transient]for lightweight, stateless services that need fresh instances - Always implement
INamedfor content objects to enable source generation - Use the generated enums for type-safe content access
- Leverage
ToNamedDictionary()for performance when working withINamedcollections
MIT License - see the license file for details.