KittyDI is a lightweight dependency injection container. I built it mainly to understand how dependency injection containers work.
While this documentation is only a brief show of features that KittyDI offers, there is a full fledged, prosaic Tutorial.
To resolve an instance of a class, use the Resolve<T>
method.
KittyDI will try to determine how to resolve the type in the following order:
- If the type has been resolved previously, the existing factory for the type will be used
- If the type has a parameterless constructor, it will be used
- If the type has only one constructor, its parameters will be resolved and it wil be used
- If the type has multiple constructors that use parameters and one is marked with the
ProvidingConstructor
attribute, its parameters will be resolved and it will be used - If all of the above fails, an
NoSuitableConstructorFoundException
is thrown
To resolve more than one instance of a type, you can resolve a Func<T>
which is a function that resolves an instance each time it is called.
Trying to resolve an interface will by default throw a NoSuitableConstructorFoundException
.
In order to resolve an instance of a type which implements the interface, use RegisterInstance<TContract,TImplementation>
.
This tells KittyDI to resolve TImplementation
instead of the requested TContract
Registering an implementation leands KittyDI to know how to instantiate the registered implementation and its recursive dependencies.
There are multiple ways to tell KittyDI to only create a single instance of a type and serve that instance on each resolution.
- Some
Register*
-functions have an optional boolean parameterisSingleton
. - Decorating the registered type with the
Singleton
attribute. - Registering a already created instance using `RegisterInstance´
By default KittyDI will create instances of singletons when they are first resolved. This behavior can be influenced when the Singleton
-Attribute is used by setting the Create
-property.
There are three possible settings:
- Create the instance on first resolution of the type (default)
- Create the instance immediately on registration
- Create the instance when
InitializeServices
is called
The class Registrar
can be used to scan Assemblies for types to register.
The short usage instructions are:
- Use
Add
orAddAssemblyOf<T>
to add Assemblies to the Registrar to be scanned - Set
InterfaceHandling
to specify when implementing an interface triggers registration of a typeNoInterfaceRegistration
: The registrar will ignore all interfacesRegisterContractsOnly
(default): Types that implement interfaces which are decorated with theContract
attribute will be registered as implementation of the interfaceRegisterAllImplementedInterfaces
: Treat all interfaces as if they have theContract
attribute.
- Set
AbstractImplementationHandling
to specify when implementing an abstract class triggers registration of a typeNoRegistrationOfAbstractImplementations
: The registrar will ignore all abstract classesRegisterContractsOnly
(default): Types that implement abstract classes which are decorated with theContract
attribute will be registered as implementation of the abstract classRegisterAllImplementations
: Treat all abstract classes as if they have theContract
attribute.
- Set
TypeHandling
to specify when types will be registered (regardless of their implemented interfaces or abstract classes)NoTypeRegistration
: Don't register types (except for registering an implementation of a contract - see the other two properties)RegisterContractsOnly
(default): Register all types that have aContract
attributeRegisterAllTypes
: Register every type found in the assemblies
- Call either
CreateContainer
to create a new container with the current settings or callRegisterToContainer
to perform registration of types and implementations to an existing container
If you don't set any of the properties, the default behavior will be to only consider types, interfaces and abstract classes that have been decorated with the Contract
attribute