dependency_injection 4.5.0
dotnet add package dependency_injection --version 4.5.0
NuGet\Install-Package dependency_injection -Version 4.5.0
<PackageReference Include="dependency_injection" Version="4.5.0" />
<PackageVersion Include="dependency_injection" Version="4.5.0" />
<PackageReference Include="dependency_injection" />
paket add dependency_injection --version 4.5.0
#r "nuget: dependency_injection, 4.5.0"
#:package dependency_injection@4.5.0
#addin nuget:?package=dependency_injection&version=4.5.0
#tool nuget:?package=dependency_injection&version=4.5.0
Overview
This library provides an implementation of a dependency injection container based on constructor injection. All instances are dealt with as std::shared_ptr<T>. Lifetime of each instance can be configured with an enum "lifetime" when registering types.
The most typical way to register a type "T" is to use a method register_type<T>(). This method registers a single constructor of the type "T" (The type "T"
needs to have only one constructor to deduce an appropriate constructor unless a factory method or an instance is registered instead of the type constructor). Each constructor argument type "Arg" is automatically resolved and injected to the constructor as "std::shared_ptr<Arg>". This is done recursively until no argument resolution is required.
Constructor arguments can also be std::vector or std::list of std::shared_ptr<Arg>. In this case, all registrations associated with the type "Arg" are collected and injected to the constructor. One of constructor arguments can be "std::shared_ptr<container>". This allows you to inject the container itself to a class as a dependency. When lifetime of the class which owns the container is container_controlled or hierarchical, the method "unregister_all" in the container has to be called when destructing the container instance to avoid memory leak.
There are several different ways to register a type. For example, an interface type can be registered with its implementation type.
Features
- Register a type with various ways
- Resolve a registered type with automatic injection of its constructor arguments (Currently, the maximum number of arguments in a constructor is 20.)
- Lifetime management using an enum dependency_injection::lifetime
- Plug-in module is supported through container registration (Only windows now)
Example 1
Here is an example to register and resolve type dependencies.
struct A;
struct B;
struct C;
struct D;
struct E;
struct F;
struct G;
struct A
{
std::shared_ptr<B> _b;
std::vector<std::shared_ptr<C>> _cs;
std::list<std::shared_ptr<D>> _ds;
A(
std::shared_ptr<B> b,
std::vector<std::shared_ptr<C>> cs,
std::list<std::shared_ptr<D>> ds) :
_b(move(b)), _cs(move(cs)), _ds(move(ds))
{
}
};
struct B
{
std::vector<std::shared_ptr<C>> _cs;
std::shared_ptr<E> _e;
std::shared_ptr<G> _g;
B(
std::vector<std::shared_ptr<C>> cs,
std::shared_ptr<E> e,
std::shared_ptr<G> g) :
_cs(move(cs)), _e(move(e)), _g(move(g))
{
}
};
struct C
{
std::shared_ptr<F> _f;
C(std::shared_ptr<F> f) : _f(std::move(f)) {}
};
struct D
{
std::shared_ptr<E> _e;
D(std::shared_ptr<E> e) : _e(std::move(e)) {}
};
struct E
{
std::shared_ptr<container> _container;
E(std::shared_ptr<container> container) : _container(move(container)) {}
};
struct F
{
std::shared_ptr<int> _value;
F(std::shared_ptr<int> value) : _value(move(value)) {}
};
struct G
{
double _value;
G(double value) : _value(value) {}
};
struct GFactory
{
std::shared_ptr<int> _value;
GFactory(std::shared_ptr<int> value) : _value(value) {}
std::shared_ptr<G> create()
{
// Specific logic to instantiate G
return std::make_shared<G>(*_value * 10.0);
}
};
using namespace dependency_injection;
auto container = container::create();
container->register_type<A>(lifetime::per_resolve);
container->register_type<B>(lifetime::per_resolve);
container->register_type<C>(lifetime::per_resolve, "C1");
container->register_type<C>(lifetime::per_resolve, "C2");
container->register_type<D>(lifetime::per_resolve, "D1");
container->register_type<D>(lifetime::per_resolve, "D2");
container->register_type<E>(lifetime::per_resolve);
container->register_type<F>(lifetime::per_resolve);
container->register_type_with_factory<G, GFactory>(lifetime::per_resolve);
container->register_instance<int>(1);
auto a = container->resolve<A>();
Note that the container type cannot be registered but can be injected to a constructor of a type as shown in the type E in the example. Also, the type G is registered with a factory type GFactory to instruct specific logic for instantiation.
Example 2
Here is another example with a local module and a plug-in module. Code below defines sample classes and a local module "sample_module".
#include <module.h>
using namespace dependency_injection;
struct IChild
{
virtual ~IChild() = default;
};
struct Parent
{
std::vector<std::shared_ptr<IChild>> _children;
Parent(std::vector<std::shared_ptr<IChild>> children) : _children(move(children)) {}
};
struct Child1 : public IChild {};
struct Child2 : public IChild {};
class sample_module : public i_module
{
public:
virtual void on_register(const std::shared_ptr<container>& container) override
{
container->register_type<Parent>(lifetime::per_resolve);
container->register_interface<IChild, Child1>(lifetime::per_resolve, "Child1");
container->register_interface<IChild, Child2>(lifetime::per_resolve, "Child2");
}
virtual void on_initialize(const std::shared_ptr<container>& container) override {}
virtual void on_close(const std::shared_ptr<container>& container) override {}
};
The local module "sample_module" can be extended by a plug-in module like below. A plug-in module is implemented in an external dll and can be exposed by implementing "plugin_module_api.h". Here is an example of a plug-in module as "sample_plugin_module" which is implemented in an external dll.
#include <module.h>
using namespace dependency_injection;
struct Child3 : public IChild {};
struct Child4 : public IChild {};
struct sample_plugin_module : public i_module
{
virtual void on_register(const std::shared_ptr<container>& container) override
{
container->register_interface<IChild, Child3>(lifetime::per_resolve, "Child3");
container->register_interface<IChild, Child4>(lifetime::per_resolve, "Child4");
}
virtual void on_initialize(const std::shared_ptr<container>& container) override {}
virtual void on_close(const std::shared_ptr<container>& container) override {}
};
#include <plugin_module_api.h>
using namespace dependency_injection;
i_module* create_module()
{
return new sample_plugin_module();
}
void delete_module(i_module* module)
{
delete module;
}
A sample client application below consumes both the local module "sample_module" and the plug-in module "sample_plugin_module".
#include <module_manager.h>
#include <plugin_module.h>
#include <sample_classes.h>
#include <sample_module.h>
using namespace dependency_injection;
int main()
{
auto module1 = std::make_shared<sample_module>();
auto module2 = plugin_module::load(L"sample_plugin_module.dll");
auto module_manager = module_manager::create({ module1, module2 });
module_manager->register_modules();
module_manager->initialize();
auto container = module_manager->get_container();
auto parent = container->resolve<Parent>();
module_manager->close();
return 0;
}
The resultant instance of type "Parent" should contain all the children defined in both sample_module and sample_plugin_module. Dependency inversion over multiple modules is another good use case of the plug-in system.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
native | native is compatible. |
This package has no dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last Updated |
---|---|---|
4.5.0 | 172 | 3/31/2024 |
4.4.2 | 124 | 3/24/2024 |
4.4.1 | 125 | 3/24/2024 |
4.3.0 | 380 | 1/8/2023 |
4.2.0 | 341 | 12/31/2022 |
4.1.1 | 345 | 12/30/2022 |
4.1.0 | 331 | 12/30/2022 |
4.0.0 | 335 | 12/30/2022 |
3.2.0 | 596 | 10/4/2020 |
3.1.2 | 492 | 10/3/2020 |
3.1.1 | 572 | 9/27/2020 |
3.0.0 | 550 | 5/12/2020 |
3.0.0-pre002 | 456 | 5/8/2020 |
2.1.0 | 533 | 4/26/2020 |
2.0.0 | 514 | 4/19/2020 |
2.0.0-pre004 | 644 | 2/6/2020 |
1.0.2 | 594 | 10/27/2019 |
1.0.1 | 1,157 | 9/23/2019 |
1.0.0 | 777 | 9/17/2019 |
Constructor registration is fully automated.