Awesome
Doinject
Asynchronous DI Container for Unity
Documentation
Example Project
Installation
Install via Unity Package Manager
Install via Unity Package Manager Please install the packages in the following order:
https://github.com/mewlist/MewCore.git
https://github.com/mewlist/Doinject.git
About Doinject
Doinject is an asynchronous DI (Dependency Injection) framework for Unity.
The concept of asynchronous DI containers is the starting point. Unity 2022 LTS / Unity 6 are supported.
Concepts
Asynchronous DI Containers
Typical DI containers perform a synchronous process when generating registered types. However, it cannot support the asynchronous instantiation function used in Unity or instance creation methods that require some kind of asynchronous processing.
By introducing Doinject, you can use a DI container that supports instance creation and release through asynchronous processing. This allows instance creation with asynchronous loading through Addressables Asset Systems, or instance creation based on information loaded from asynchronous IO. It becomes possible to perform more flexible instance management with simple descriptions. By creating a custom factory, you can create instances that involve any asynchronous processing.
Context Space Consistent with Unity's Lifecycle
Designed to define context spaces in a way that does not conflict with Unity's lifecycle. When a scene is closed, the context associated with that scene is closed, the instances created in that context space disappear, and destroying a GameObject with context similarly closes the context. Context spaces are automatically structured by the framework, and parent-child relationships are formed when multiple contexts are loaded.
Collaboration with the Addressable Asset System
Instances from the Addressable Asset System can also be handled, and the release of load handles can be automated. Resource management in Addressables requires careful implementation, such as creating your own resource management system. However, using Doinject automates the loading and release of Addressables.
Simple coding
You can achieve replacements for the factory pattern, (context-closed) singleton pattern, and service locator pattern with simple descriptions. Additionally, by creating custom factories or custom resolvers, you can handle more complex instance creation scenarios.
Binding
Type Binding
Code | Resolver behavior | Type |
---|---|---|
container.Bind<SomeClass>(); | new SomeClass() | cached |
container.Bind<SomeClass>().AsSingleton(); | new SomeClass() | singleton |
container.Bind<SomeClass>().AsTransient(); | new SomeClass() | transient |
container.Bind<SomeClass>().Args(123,"ABC"); | new SomeClass(123, "abc") | cached |
container.Bind<ISomeInterface>().To<SomeClass>(); | new SomeClass() as ISomeInterface | cached |
container.Bind<ISomeInterface, SomeClass>(); | new SomeClass() as ISomeInterface | cached |
container.Bind<SomeClass>() <br />.FromInstance(instance); | instance | instance |
container.BindInstance(instance); | instance | instance |
MonoBehaviour Binding
Code | Resolver behavior |
---|---|
container.Bind<SomeComponent>(); | new GameObject().AddComponent<SomeComponent>() |
container <br />.Bind<SomeComponent>() <br />.Under(transform); | var instance = new GameObject().AddComponent<SomeComponent>(); <br/>instance.transform.SetParent(transform); |
container <br />.Bind<SomeComponent>() <br />.On(gameObject); | gameObject.AddComponent<SomeComponent>() |
container <br />.BindPrefab<SomeComponent>(somePrefab); | Instantiate(somePrefab).GetComponent<SomeComponent>() |
Addressables Binding
Code | Resolver behavior |
---|---|
container <br />.BindAssetReference<SomeAddressalbesObject>(assetReference); | var handle = Addressables <br />.LoadAssetAsync<GameObject>(assetReference) <br/><br/>await handle.Task |
container <br />.BindPrefabAssetReference<SomeComponent>(prefabAssetReference); | var handle = Addressables <br />.LoadAssetAsync<GameObject>(prefabAssetReference) <br/><br/>var prefab = await handle.Task <br/><br/>Instantiate(prefab).GetComponent<SomeComponent>() |
container <br />.BindAssetRuntimeKey<SomeAddressalbesObject>("guid or path"); | var handle = Addressables <br />.LoadAssetAsync<GameObject>("guid or path") <br/><br/>await handle.Task |
container <br />.BindPrefabAssetRuntimeKey<SomeComponent>("guid or path"); | var handle = Addressables <br />.LoadAssetAsync<GameObject>("guid or path") <br/><br/>var prefab = await handle.Task <br/><br/>Instantiate(prefab).GetComponent<SomeComponent>() |
Factory Binding
Code | Resolver behavior |
---|---|
container <br />.Bind<SomeClass>() <br />.AsFactory(); | var resolver = new TypeResolver<SomeClass>() <br/><br/>new Factory<SomeClass>(resolver) as IFactory<SomeClass> |
container <br />.Bind<SomeComponent>() <br />.AsFactory(); | var resolver = new MonoBehaviourResolver<SomeComponent>() <br/><br/>new Factory<SomeComponent>(resolver)) <br /> as IFactory<SomeComponent> |
container <br />.Bind<SomeClass>() <br />.AsCustomFactory<MyFactory>(); | new CustomFactoryResolver<MyFactory>() as IFactory<SomeClass> |
Can also be combined with Addressables. You can also create a factory that instantiates the asynchronously loaded prefab and calls GetComponent<T>() on it.
container
.BindAssetReference<SomeComponentOnAddressalbesPrefab>(assetReference)
.AsFactory<SomeComponentOnAddressalbesPrefab>();
[Inject]
void Construct(IFactory<SomeComponentOnAddressalbesPrefab> factory)
{
var instance = await factory.CreateAsync();
}
Injection
Installer
public class SomeInstaller : BindingInstallerScriptableObject
{
public override void Install(DIContainer container, IContextArg contextArg)
{
container.Bind<SomeClass>();
}
}
Constructor Injection
class ExampleClass
{
// Constructor Injection
public ExampleClass(SomeClass someClass)
{ ... }
}
Method Injection
class ExampleClass
{
// Method Injection
[Inject]
public Construct(SomeClass someClass)
{ ... }
}
Injection to MonoBehaviour
// Inherits IInjectableComponent
class ExampleComponent : MonoBehaviour, IInjectableComponent
{
// Method Injection
[Inject]
public void Construct(SomeClass someClass)
{ ... }
}