Inyección de Dependencias

DependencyInjection

🌍 Idioma: English | Español

Contenedor IoC/DI para Delphi con una API fluida inspirada en Microsoft.Extensions.DependencyInjection de .NET. Registra servicios una vez, resuélvelos en cualquier parte — con tiempos de vida Singleton, Scoped y Transient.

Delphi 12+ Licencia


¿Por qué usarlo?

  • 🔌 API familiar — Los mismos métodos AddSingleton / AddTransient / AddScoped que en .NET
  • 🎯 Genérico y type-safe — Verificación en tiempo de compilación mediante genéricos, sin tokens de cadena
  • Tres modos de vida — Singleton, Scoped (por scope) y Transient (nueva instancia siempre)
  • 🏭 Registro flexible — Por clase, por lambda de factoría o por instancia existente
  • 💤 Resolución diferidaLazy.From<T>() pospone la creación hasta el primer uso
  • 🦆 Duck TypingTDuckDecorator<T> envuelve cualquier objeto que implemente la misma forma de interfaz
  • 📦 Sin dependencias externas — Solo depende de DependencyInjection.Abstractions

Inicio rápido

uses
  Daf.Extensions.DependencyInjection,
  Daf.DependencyInjection;

var
  Services: IServiceCollection;
  Provider: IServiceProvider;
begin
  Services := TServiceCollection.Create;

  // Registrar
  Services.AddSingleton<IMyService, TMyService>;

  // Construir el contenedor (congela la colección)
  Provider := Services.BuildServiceProvider;

  // Resolver
  var Svc := Provider.GetRequiredService<IMyService>;
  Svc.DoWork;

  // Siempre hacer Shutdown al finalizar
  Provider.ShutDown;
end;

Sobrecargas de registro

// Por clase de implementación
Services.AddSingleton<IMyService, TMyServiceImpl>;

// Por lambda de factoría (control total)
Services.AddTransient<IMyService>(
  function(P: IServiceProvider): IMyService
  begin
    Result := TMyServiceImpl.Create(P.GetRequiredService<IConfig>);
  end);

// Por instancia existente (solo Singleton)
Services.AddSingleton<IMyService>(MyExistingInstance);

Scopes

var Scope := Provider.CreateScope;
try
  var Svc := Scope.ServiceProvider.GetRequiredService<IScopedService>;
  // Las instancias Scoped son únicas dentro de este scope
finally
  Scope := nil; // dispara Shutdown + limpieza gestionada
end;

Patrón AppModule

Organiza los registros por módulo:

type
  TMyModule = class(TInterfacedObject, IAppModule)
    procedure AddServices(const Services: IServiceCollection);
  end;

procedure TMyModule.AddServices(const Services: IServiceCollection);
begin
  Services.AddSingleton<IMyService, TMyService>;
  Services.AddTransient<IOther, TOtherImpl>;
end;

Consulta DependencyInjection.Abstractions para la interfaz IAppModule y todos los contratos clave.


Documentación

  • 📖 Guía de uso — tiempos de vida, scopes, Lazy, DuckDecorator, integración con Hosting

Abstracciones

DependencyInjection.Abstractions

🌍 Idioma: English | Español

Contratos principales (interfaces y tipos) del sistema de Inyección de Dependencias de DAF. Este módulo no contiene implementación — define la forma de la que dependen los consumidores y que DependencyInjection implementa.

Delphi 12+ Licencia


Qué hay en este módulo

Unidad Contenido
Daf.Extensions.DependencyInjection IServiceCollection, IServiceProvider, IServiceScope, tiempos de vida, Factory, TDuckDecorator<T>, Lazy
Daf.AppModule IAppModule — patrón de registro por módulo
Daf.DependencyInjection.ActivatorUtilities Helpers para construir objetos mediante RTTI con argumentos resueltos por DI

Tipos clave

IServiceCollection

Constructor fluido para registrar servicios antes de construir el contenedor.

Services
  .AddSingleton<ICache, TMemoryCache>
  .AddTransient<IRepo, TRepoImpl>
  .AddScoped<IUoW, TDbUoW>;

var Provider := Services.BuildServiceProvider;

IServiceProvider

El contenedor resuelto. Úsalo para obtener instancias de servicios.

var Svc := Provider.GetRequiredService<IMyService>;
var Opt: IMyService;
if Provider.TryGet<IMyService>(Opt) then ...
var All := Provider.GetServices<IPlugin>;

TServiceLifeTime

type TServiceLifeTime = (Singleton, Scoped, Transient);

IServiceScope

Frontera de tiempo de vida. Los servicios Scoped se comparten dentro de un scope y se liberan cuando este termina.

var Scope := Provider.CreateScope;
var Svc := Scope.ServiceProvider.GetRequiredService<IScopedService>;
Scope := nil; // libera las instancias Scoped

IAppModule

Convención para agrupar registros de servicios:

type
  IAppModule = interface(IInvokable)
    procedure AddServices(const Services: IServiceCollection);
  end;

Factory

Helper para construir un TServiceFactory desde una clase o instancia:

Services.Add(TypeInfo(IMyService), Singleton, Factory.From(TypeInfo(IMyService), TMyImpl));

TDuckDecorator<T>

Clase base para envolver un servicio con lógica pre/post-llamada sin herencia. Sobreescribe BeforeCall / AfterCall.

Lazy

Result := Lazy.From<IHeavy>(Provider, function(P): IHeavy begin Result := THeavy.Create end);

Dependencias

Este módulo no depende de ningún otro módulo DAF. Solo requiere la RTL de Delphi (System.Rtti, System.Generics.Collections).

La implementación está en DependencyInjection.