Fast and easy to use dependency injection library for Unity game engine.
- Delegate based reflection hooks for ultra fast resolving speed.
- Caching reflection data for reducing allocations.
- Small codebase.
- Easy to use.
- DOES NOT CONTAIN UNNECESSARY FUNCTIONALITY like other popular DI frameworks.
- Field injection.
- Property injection.
- Method injection.
- Injection lifetime.
- Local scope injection.
Requires a version of unity that supports path query parameter for git packages (Unity 2021.3 or later). You can add a reference https://github.com/arty-F/UniDI.git?path=Assets/UniDI
to Package Manager.
Download the latest .unitypackage
file from releases page and import downloaded package into unity.
- Mark field/property/method into which the dependency should be injected with the
[Inject]
attribute.
using UniDI;
public class TestClass
{
[Inject] private InjectedClass1 _injectedField;
[Inject] public InjectedClass2 InjectedProperty { get; private set; }
[Inject]
public void Method(InjectedClass3 p1, InjectedClass4 p2)
{
_injectedFromMethod1 = p1;
_injectedFromMethod2 = p2;
}
private InjectedClass3 _injectedFromMethod1;
private InjectedClass4 _injectedFromMethod2;
}
- Inject instances by invoking
Inject()
method. You can use generic version ofInject<>()
method onGameObject
where the generic type parameter will represent the type ofGameObject
component that needs to be injected.
using UniDI;
...
[SerializeField] GameObject _gameObjectPrefab;
[SerializeField] InjectedComponent _typedPrefab;
...
//plain C# class injecting
var csharpClass = new InjectedClass();
csharpClass.Inject();
//bad way GameObject component injecting
var gameObjectInstance1 = Instantiate(_gameObjectPrefab);
gameObjectInstance1.GetComponent<InjectedComponent>().Inject();
//good way GameObject component injecting
var gameObjectInstance2 = Instantiate(_gameObjectPrefab);
gameObjectInstance2.Inject<InjectedComponent>();
//best way GameObject component injecting
InjectedComponent typedInstance = Instantiate(_typedPrefab);
typedInstance.Inject();
- Resolve dependencies of injection consumer classes by invoking
Resolve()
method. Or you can useGameObject
extension method on prefab to one row instantiate and resolving dependencies (has 9 overloads like original Instantiate method). AfterGameObject
resolving all injected dependencies will be available inStart
method (inAwake
andOnEnable
they still will benull
).
using UniDI;
...
[SerializeField] GameObject _gameObjectPrefab;
[SerializeField] ConsumerComponent _typedPrefab;
...
//plain C# class resolving
var csharpClass = new TestClass();
csharpClass.Resolve();
//bad way GameObject resolving
GameObject gameObjectInstance1 = Instantiate(_gameObjectPrefab);
gameObjectInstance1.GetComponent<ConsumerComponent>().Resolve();
//good way GameObject resolving
GameObject gameObjectInstance2 = _gameObjectPrefab.InstantiateResolve<ConsumerComponent>();
//best way GameObject resolving
ConsumerComponent typedInstance = _typedPrefab.InstantiateResolve(position, rotation);
You can specify the lifetime of the injection:
Lifetime.Game
(default) : the dependency will exist as long as the application is running.Lifetime.Scene
: dependencies will be cleared every time the active scene changes.
var injectedClass = new InjectedClass();
injectedClass.Inject(Lifetime.Scene);
By default, all injected classes will be placed in the global scope. In order to set the local scope for dependency injection, you must specify the scope identifier based on int
when injecting and resolving dependencies. When using resolve for local scope if the dependency was not found in the specified local scope, then they will try to find it in the global scope. By this way you can inject both global and local dependencies into one consumer.
public class Consumer : MonoBehaviour
{
[Inject] private GlobalInjectionClass _field1;
[Inject] private LocalInjectionClass _field2;
}
...
int id = consumer.GetInstanceID();
var globalInjectionClass = new GlobalInjectionClass();
globalInjectionClass.Inject();
var localInjectionClass = new LocalInjectionClass();
localInjectionClass.Inject(id);
consumer.Resolve(id);
You can override or clear previously injected dependencies. For overriding just use Inject()
on new instance. For clearing use ReleaseDependency()
on same type instance.
- Global scope dependency clearing by
ReleaseDependency()
. - Local scope dependency clearing by
ReleaseDependency(id)
whereid
is a local scopeint
type identifier. By default this type of clear deletes the entire local scope. To avoid completely clearing the local scope you must pass a value ofclearFullScope
isfalse
, like thatReleaseDependency(id, false)
. By passing thisfalse
value you will clear only the type on which this method was called in the specified local scope.
globalDependencyInstance.ReleaseDependency(); //clear globalDependencyInstance in global scope
localDependencyInstance1.ReleaseDependency(id); //clear all dependencies in specified local scope
localDependencyInstance2.ReleaseDependency(id, false); //clear localDependencyInstance2 in specified local scope
Optionally you can configure parameters of a library and get some performance boost. Settings window is located in the menu item Tools
-> UniDI
-> Settings
. Basically, these settings control the number of different cached items collections that can hold before it needs to be resized.
four fields in instance, different types
Time | GC Alloc | |
---|---|---|
1 instance | 13 ms | 46 KB |
100 instances | 15 ms | 80 KB |
1000 instances | 28 ms | 389 KB |
four properties in instance, different types
Time | GC Alloc | |
---|---|---|
1 instance | 4 ms | 21 KB |
100 instances | 6 ms | 56 KB |
1000 instances | 20 ms | 365 KB |
four method parameters, different types
Time | GC Alloc | |
---|---|---|
1 instance | 3 ms | 19 KB |
100 instances | 4 ms | 19 KB |
1000 instances | 6 ms | 19 KB |