Extremely simple, fast and clear Dependency Injection (DI) and Inversion of Control (IOC) container.
Features
- Helping resolving dependencies initialisation order easily
- Pure Dart library, no Flutter dependency
- Dependency Injection by explicit Type or by Interface
- "Lazy" instantiating
- Singletons and Multiple dependencies (see
getAllfor details) - Resolution context with current dependency tree for automatic loggers definition and similar tasks
- Nested containers with the dependencies overriding
- Releasing declared bindings together with their cached instances (see
releaseandreleaseAll) - Easy debug: clear errors messages about missing dependencies with exact dependency tree description
Getting started
Simply add as a dependency in pubspec.yaml
Usage
Please follow to /example folder for simple console application template example.
final di = DI();
di
..bind(to: (c) => createLogger(c.plan[c.plan.length - 2]), dynamic: true)
..bind(to: (c) => AppConfig)
..bind(to: (c) => AppController(appConfig: c.get(), logger: c.get()));
Bindings can be dropped at any moment. release removes the binding declaration
of the given type and the instance cached for it, so the container simply forgets
them — no disposing is performed:
di.release<AppController>();
Just like get, release expects the type to be declared once. Multiple
declarations are dropped all together by releaseAll, the counterpart of getAll:
di.releaseAll<RequestInterceptor>();
Only the container the method is called on is affected: bindings declared in parent containers are left intact and still resolvable through the hierarchy.
Nested containers
A nested container declares its own bindings and inherits the rest from the
parent. The closest declaration wins, so the dependency can be substituted
for a single scope without touching the upstream containers — the overridden
binding is not instantiated at all:
final root = DI()..bind<AppConfig>(to: (c) => ProductionAppConfig());
final sandbox = DI(parent: root)..bind<AppConfig>(to: (c) => SandboxAppConfig());
sandbox.get<AppConfig>(); // SandboxAppConfig
root.get<AppConfig>(); // ProductionAppConfig
getAll keeps collecting the whole hierarchy, the closest declarations first,
so the multi injection still works across the nested containers.
Releasing is a management operation, not a part of the resolution: calling it from inside an instance factory throws, since the dependency tree being built at the moment would become inconsistent.