Inversion of Control
Definition
Inversion of Control, or in short IoC, aka Dependency Inversion or in short DI is one of the basic principles of SOLID code. Basically it allows the code to be less brittle, more testable and extensible to be forwards-compatible with future design/spec changes.
Dependencies
Whenever you use dependency injection throughout the development, the consuming code gets injected with its dependencies without knowing the actual implementation details and/or the lifetime style of the dependency. Each typical dependency lifecycle contains 3 stages: Register -> Resolve -> Release. The framework exposes correspondent abstractions via IDependencyRegistrator
and IDependencyResolver
interfaces not limiting the user to any particular implementation. There are plenty of existing adapters to be used and if a new IoC container is added an adapter can be created within minutes. The existing abstractions expose all kinds of lifetime styles and registration options meeting various scenarios.
Registration
There are various ways to register a dependency. You can specify its lifetime style and use either generic or non-generic flavor depending on which suits your needs better:
void IDependencyRegistrator.RegisterTransient() where TImplementation : class, TDependency;
void IDependencyRegistrator.RegisterSingleton(Type serviceType, Type implementationType);
and many more. You should always register dependencies during the app startup and avoid re-registration or de-registration as this can introduce hardly traceable and reproducible bugs.
Resolution
As a rule of thumb you should never explicitly resolve a dependency inside your code. The explicit resolution should only be used by the infra code for internal resolutions and never directly by the user inside the app. Explicit resolution can lead to unexpected consequences like getting a dependency with different lifetime style, implementation etc. Opt for injection instead - preferably via constructor; in case it's not available use either property injection or an ambient context to get the dependency. in case you still decide to use resolution you can always get the dependency via:
TDependency IDependencyResolver.Resolve() where TDependency : class;
object IDependencyResolver.Resolve(Type dependencyType);
Release
The release is managed by the IoC container itself and is not expected to be called explicitly unless the whole container is disposed. Hence the convention is to put all release-related code into the implementation of the IDisposable
interface suggesting it will be invoked on the container disposal
Last updated