Reflex is an Dependency Injection framework for Unity. Making your classes independent of its dependencies, granting better separation of concerns. It achieves that by decoupling the usage of an object from its creation. This helps you to follow SOLID’s dependency inversion and single responsibility principles. Making your project more readable, testable and scalable.
- Blazing fast
- IL2CPP Friendly
- Minimal code base
- Contructor injection
[Inject]
Property, field and method injection attribute- Debugging Window
Resolving ten thousand times a transient dependency with four levels of chained dependencies. See NestedBenchmarkReflex.cs.
Mono | IL2CPP | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
Mono | IL2CPP | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
The performance on
IL2CPP (AOT)
backend is not so good because the expressions are actually interpreted, unlikeMono (JIT)
, where they are actually compiled.
I'm investigating whether dealing with IL Reweaving is worth the complexity it brings.
Requires Unity 2019+
https://github.com/ilyxa-banchichi/reflex.git?path=/Assets/Reflex/
- Download the .unitypackage from releases page.
- Import Reflex.X.X.X.unitypackage
Create a Installer to install your bindings in the project context, and remember to add this component in the ProjectContext prefab, and reference it in the Installers list of the ProjectContext. See ProjectContext.prefab.
public class ProjectInstaller : Installer
{
public override void InstallBindings(Container container)
{
container.BindInstance<int>(42);
container.BindTransient<IDependencyOne, DependencyOne>();
container.BindSingleton<IDependencyTwo, DependencyTwo>();
}
}
Be aware that fields and properties with [Inject] are injected only into pre-existing MonoBehaviours within the scene after the SceneManager.sceneLoaded event, which happens after Awake and before Start. See MonoInjector.cs.
If you want to instantiate a MonoBehaviour/Component at runtime and wants injection to happen, use the
Instantiate
method from Container.
public class MonoBehaviourInjection : MonoBehaviour
{
[Inject] private readonly Container _container;
[Inject] public IDependencyOne DependencyOne { get; private set; }
[Inject]
private void Inject(Container container, IDependencyOne dependencyOne)
{
var dependencyTwo = container
.Resolve(typeof(IDependencyTwo));
}
private void Start()
{
var dependencyTwo = _container
.Resolve(typeof(IDependencyTwo));
var answerForLifeTheUniverseAndEverything = _container
.Resolve<int>();
}
}
public class NonMonoBehaviourInjection
{
private readonly Container _container;
private readonly IDependencyOne _dependencyOne;
private readonly int _answerForLifeTheUniverseAndEverything;
public NonMonoBehaviourInjection(Container container, IDependencyOne dependencyOne, int answerForLifeTheUniverseAndEverything)
{
_container = container;
_dependencyOne = dependencyOne;
_answerForLifeTheUniverseAndEverything = answerForLifeTheUniverseAndEverything;
}
}
Events |
---|
SceneContext.Awake(DefaultExecutionOrder(-10000)) |
↓ |
Reflex.Injectors.SceneInjector.Inject |
↓ |
MonoBehaviour.Awake |
↓ |
MonoBehaviour.Start |
Reflex.Injectors.SceneInjector.Inject
injects fields, properties and methods decorated with [Inject] attribute.
A single prefab named ProjectContext
that should live inside a Resources
folder and should contain a ProjectContext
component attached
Non-Obligatory to have
A single root gameobject per scene that should contain a SceneContext
component attached
Non-Obligatory to have, but scenes without it wont be injected
Its a ReflexConfiguration
scriptable object instance, named ReflexConfiguration
that should live inside a Resources
folder.
It can be created by menu item Reflex → Configuration → Create Configuration.
Non-Obligatory to have but projects without it will fallback using following default configuration
- LogLevel: Default (Info, everything gets logged by default)
Used by our internal logger so developers can define desired logging verbosity level.
Binds a function to a type. Every time resolve is called to this binding, the function binded will be invoked.
Binds a object instance to a type. Every time resolve is called, this instance will be returned.
Instances provided by the user, since not created by Reflex, will not be disposed automatically, we strongly recomend using BindSingleton.
Binds a factory. Every time the resolve is called, a new instance will be provided.
Instances will be disposed once the container that provided the instances are disposed.
Binds a factory. Every time the resolve is called, the same instance will be provided.
The instance will be disposed once the container that provided the instance are disposed.
To access the debugging window on unity menu bar click Reflex
→ Debugger
Through the debugging window you can visualize:
- Container hierarchy
- Bindings
- Resolution count
Reflex is licensed under the MIT license, so you can comfortably use it in commercial applications (We still love contributions though).