VContainer
VContainer copied to clipboard
[Feature Request] Lazy inject
Like the https://github.com/hadashiA/VContainer/issues/508#issuecomment-1519579824 says. I think lazy inject should be a thing. Syntax can be like
[Inject] internal Lazy<T> LazyInjected
+1, Also with UniTask inject AsyncLazy<T>?
I think when using [Inject] attribute on a property / field, this is already lazy. In my understanding vcontainer does everything lazy (resolve it, when you need it).
I think when #508 would have used property / field injection for the statemanager and the rest in the constructor instead of method injection, it might have worked out. The statemanager can be build completely and the first time the bootstate would need the statemanager, it would then resolve it.
But in general, you should avoid circular dependencies, since this is at least for me a code smell. There are some patterns to solve circular dependencies, e.g. an aggregate for coupling on top.
VContainer creates the instances at the moment of injection @lolhans
I need to admit that Im not 100 percent sure, but I think using the [Inject] attribute for property injection in VContainer can indeed help resolve circular dependencies that occur with constructor injection. This is because property injection allows the creation of instances without needing all dependencies to be resolved upfront, as is the case with constructor injection.
Here's how it works:
Constructor Injection: When you use constructor injection, all dependencies of a class must be resolved before the class itself can be instantiated. If Class A depends on Class B and vice versa, this creates a circular dependency that cannot be resolved, leading to an error.
Property Injection: With property injection, instances of classes can be created even if not all dependencies are immediately available. After the instances are created, the dependencies are then "injected" into the properties marked with the [Inject] attribute. This allows VContainer to first create instances of both Class A and Class B, and then resolve the dependencies.
Here's a basic example:
public class ClassA
{
[Inject]
public ClassB B { get; set; }
}
public class ClassB
{
[Inject]
public ClassA A { get; set; }
}
In this setup, I think VContainer can create instances of ClassA and ClassB without immediately needing the other, and then inject the dependencies afterward, when it is needed the first time.
Unfortunately I cannot verify this approach, since I have no computer available right now. But I think I have done this in a recent project. Could someone please check this out? @AlonTalmi
It won't work, while makes sense and technically can be supported, that's not the case and I guess it's by design.
The injection and resolution systems are completely separate. Injection is as simple as going over all the type's members and calling Resolve(memebrType) from the container, there is no separate CreateInstance() method and Inject() method.
Also if I might add, circular dependency is usually considered code smell whether it's supported or not.
Okay, when you have actually tried that, you are propably right on that. Yeah, I already mentioned in a comment earlier, that you should avoid circular dependency in general.
You're right, I apologize!
Hey @SettingDust, based on our discussion here, do you think the approach with property injection and the [Inject] attribute addresses your concern regarding Lazy Injection in VContainer?
It is always possible to introduce a separate util class like "GameSystem" or any name to avoid circular dependencies. But I don't think it's the solution to lazy inject. The lazy injection I propose here leans toward framework design rather than "What should I do"
Maybe I wasn't clear enough. I think using a mix of cunstructor injection and (lazy) field / property injection already does the job of breaking the circular dependency. Just move out the circular dependency from constructor to a property and add the Inject attribute to it.