Skip to content

Repository files navigation

SimpleInjection

A lightweight dependency injection library for C# that combines simple DI container functionality with powerful source generation for content management.

Features

🚀 Simple Dependency Injection

  • 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

⚡ Content Source Generation

  • 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

Quick Start

1. Install the Package

dotnet add package SimpleInjection

2. Dependency Injection Usage

Mark 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>();

3. Content Generation Usage

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);

Advanced Features

Performance Optimizations

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>());

SubContent Collections

For hierarchical content organization:

publicclassWeaponStats:ISubContent<Material,int>{publicDictionary<Material,int>ByKey{get;}publicintthis[Materialmaterial]=>ByKey[material];}

Roslyn Analyzers

The package includes analyzers that help you:

  • NC001: Ensures Dictionary<TKey, TValue> uses NamedComparer<T> for INamed keys
  • TND001: Suggests using ToNamedDictionary() instead of ToDictionary() for INamed keys

Requirements

  • .NET 8.0 or .NET 9.0
  • C# with nullable reference types enabled (recommended)

How It Works

  1. Service Discovery: The host scans all loaded assemblies for classes marked with lifetime attributes
  2. Dependency Resolution: Constructor parameters are automatically resolved from registered services
  3. Source Generation: The generator scans for classes implementing IContent<T> and generates enums and helper methods
  4. Code Analysis: Roslyn analyzers ensure best practices for dictionary usage with named keys

Best Practices

  • 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 INamed for content objects to enable source generation
  • Use the generated enums for type-safe content access
  • Leverage ToNamedDictionary() for performance when working with INamed collections

License

MIT License - see the license file for details.