Hello everyone!
I have learned VContainer from videos and documentation. But i feel like i am missing some features and i cant use it in my projects effectively. Because of this i am searching a medium-big sized project to examine and learn from it. I have searched github and examine many project but they has very basic examples. If anyone has anadvenced project and able to share, i will use it only for learning purposes.
Thanks in advance!
Not sure what this weird fascination with forcing Unity to play well with third party DI is… it’s almost like a religion or something. Why people don’t just use scenes and prefabs for dependency injection is beyond me… that’s what they are and that’s what they are designed for.
If you insist on using third party stuff, you’re really kind of on your own. My experience was that it was dreadful and led ultimately to the cancellation of a massive multi-year project when the technical burden imposed by blindly reaching for third party injectors crushed all forward progress.
Good luck!
I have used VContainer extensively, is there any particular questions you have?
Unity uses VContainer in one of their official repos:
My recommendation is to only use VContainer for application scope services. IoC Container is not very suited for gameplay and is incompatible with certain game design patterns such as object pooling and scene serialization.
I think it could have some value for injecting dependencies to backend services, cloud save, leaderboards, analytics etc.
However event the creator of VContainer recommends not injecting into Monobehaviours. Essentially the entire game should just be treated as a view, the vast majority of games do not require ‘business logic’ and therefore have little use for DI Container.
You will probably learn more about IoC Container by building a .NET application then you will trying to force it into Unity.
Yeah i don’t like using it much but employers expecting us to use it right now. So I have to learn and use it for my portfolio. Thank you!
I don’t have a spesific question. I just need more usage example. You already answer this with your recommendations. Thank you!
I have to agree with Kurt. In particular with an example (learning) project like BossRoom (mentioned above) to use VContainer excessively only served to make the code confusing. There was nothing I could relate to. After an hour of looking through the code I set it aside because it wasn’t going to help me in any way. But if you intend to use VContainer I suppose it might be a best practice project.
But if it’s true that even VContainer itself recommends not to use it with MonoBehaviour, that’s not what BossRoom is doing.
I still recall the discussion where one person was adamant on providing use cases where DI improved the code.
And I responded with something like:
Yeah, just do:
theRef = GetComponent<TheComponent>();
Ah, okay, in that case:
theRef = GetComponentInChildren<TheComponent>();
Oh, MonoBehaviour has no ctor? Right.
theRef = AddComponent<TheComponent>();
theRef.InitWithReferences(root, healthbar, dataSO);
That, too, is dependency injection right there and it requires just one method and three assignments. Compared to an attribute and three lines of registration, DI merely changes the syntax and makes the code less debuggable.
And DI doesn’t even speed things up, it’s just going to hide the fact that it might just do GameObject.Find or whatever on your behalf.
DI is best left to unit testing to inject mock classes - that’s where I feel the pain the most, but not nearly enough to introduce DI.
Are you starting a new job and that’s what they use?
Or did the CTO just decide to force DI upon everyone? Perhaps they have good reasons (ie unit tests, extreme flexibility needed in some parts of the code), or perhaps they simply fell to the hype as the person I mentioned.
If everyone subscribes to it, and at least one dev is sufficiently knowledgeable on the subject, go for it. If however there is severe friction to introduce DI, with a lack of concrete benefits for the very project you work on, and no one on the team has used it much before - it might just do what Kurt said: kill the project.
Your experience was likely with the containerized dependency injectors which I second are awful for Unity, but not because I think DI is awful as much as I think containerized DI is awful. If it hadn’t been for Init(args) I don’t think I ever would have tried DI in Unity. Yes, I can replicate the functionality without it, but I like being able to mark something with an attribute and the system just spawns it for me either immediately or on an as needed basis into DDOL. I can even optionally specify a prefab or a scene (scenes are a recent feature but prefab support has been around for a while) and it’ll create it from that instead.
Here’s a one line version.
using UnityEngine;
using System.Linq;
using System.Reflection;
public static class ComponentExtensions
{
public static T AddComponentWithInit<T>(this GameObject gameObject, params object[] args) where T : Component
{
T component = gameObject.AddComponent<T>();
MethodInfo method = typeof(T)
.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.FirstOrDefault(m =>
m.Name == "Init" &&
m.GetParameters().Length == args.Length &&
m.GetParameters()
.Select(p => p.ParameterType)
.Zip(args.Select(a => a?.GetType()), (pType, aType) => aType == null || pType.IsAssignableFrom(aType))
.All(match => match));
if (method != null)
{
method.Invoke(component, args);
}
return component;
}
}
using UnityEngine;
public class SomeScript : MonoBehaviour
{
[SerializeField] private string Text;
[SerializeField] private float Value;
private void Init(string text, float value)
{
Text = text;
Value = value;
}
}
gameObject.AddComponentWithInit<SomeScript>("Hello world.", 3.14f);
They are likely hyped for it. I have seen this requirement on job applications in the past year. Maybe hype is just gone by now but I dont know.
Thank you i will look into it.
And if the latter, explain to the CTO that Unity’s entire scene / prefab hierarchy IS actually DI.
Can you elaborate what you mean by IoC containers being incompatible with scene serialization? It is entirely possible to register scene-scoped services in an IoC container, or to override a certain service only for all the clients belonging to a certain scene or a prefab. But perhaps you just mean that it’s too difficult to do in VContainer to be worth the effort. Since Unity already does support wiring services within the boundaries of a scene very easily using serialized fields, leveraging an IoC container is certainly often less useful in this situation.
Also, I do think a DI framework can actually go very well together with the object pool pattern, because it can be leveraged to automate the returning of services to the object pool when a client is destroyed. Same thing with Addressables, the observer pattern, and IDisposable services. It’s very easy to create resource leaks by accident when you have to just manually remember to implement the code for disposing objects for every client separately.
But I agree with the overall sentiment that an IoC container is most useful for resolving project-scoped services in Unity. That’s for sure the biggest pain point in Unity if you don’t use any kind of a DI framework in my experience. Dependency injection can offer a huge number of benefits over using the Singleton pattern, with no major downsides.
From my experience, you should only use a DI container in system code, not in game code. For example, if you have a system that can be reused in many games and each game needs to inject different dependencies into that system, you can use a DI container in this case.
Using DI in game code is over-engineering, since it hides the dependencies being injected behind a black box (the DI container). If you’re working in a team, you’ll have to train every new member on how to use the DI container and what dependencies have been injected. As your game code becomes more complex, you might not even know what dependencies you’re working with, because anyone in your team can inject anything from anywhere in the codebase.
Serialized fields are a form of dependency injection, and I have never heard anybody say that they are too complicated to learn, or make it too difficult to understand what services are going to get injected to a client.
If the services that have been configured with an IoC container are visualized in the Inspector similar to serialized fields, then in my experience that pretty much makes those potential pain points go away entirely. Serialized fields can also receive services from anywhere in the entire project, but since they are visualized and pingable in the Inspector, it’s a non-issue.
In the case of Unity, using a DI framework can also be very useful simply for enabling code-based pure dependency injection. Unit testing components is very painful by default because they don’t support constructor injection, and a DI framework can be used to completely solve this problem.
Many people seem to like to use a DI framework as a substitute for using MonoBehaviours and the Inspector, but I like to do the opposite.
I think all the advice from this thread is anwered my questions. Let me summarize it.
-
Best use case for DI is sytem code or application scope services. This means that systems that are reused often on the game can use DI. It could have some value for injecting dependencies to backend services, cloud save, leaderboards, analytics etc.
-
Unity’s entire scene/prefab hierarchy is actually a type of DI.
-
There is new options for DI like Init(args). You can check it out. It has a free lite version.
-
VContainer is not recommended to use with Monobehaviors. This warning is from documantation.
-
If there is someone on the team suffieciently knowledagle on the subject we can use it and learn from them.
Thank you everyone for your answers.