Any fans of Dependency Injection? New framework released.

Any other Unity devs familiar with the concept of a dependency injection framework? If not you should consider finding out! It is, in my opinion, invaluable when creating any kind of non-trivial software.

Our company has been happily using a DI framework for Unity that we wrote internally and have recently decided to open-source it so others can benefit. You can get it for free in the Unity Asset store here:

We are all “dependency injection” junkies at my company but when we moved to Unity we couldn’t find anything that met our needs, so we rolled our own! It is similar to Strange IoC if you’ve heard of that except that it’s more of a pure dependency injection framework (and also has a fairly different feature set)

We give a basic introduction to the idea on the documentation page (which you can find here: GitHub - modesttree/Zenject: Dependency Injection Framework for Unity3D)

What’s everyone’s experience/understanding of DI?

1 Like

I just gave the package a quick look, and I’m sorry, but I don’t understand what it’s supposed to bring to my own projects. Maybe you could explain the advantages?

These articles explain the motivation better than I could:

In a nutshell, the default way to Unity encourages us to manage dependencies between different game classes/components (that is, using singletons or public members in MonoBehaviours, or GameObject.find) are all flawed in their own way. Dependency injection frameworks offer a very nice solution to this problem.

The tricky thing is, it’s hard to appreciate the benefits at first because it really only becomes obvious once you start getting into larger projects.

I should also mention that there are many other benefits that result from using DI which include

  • Testability of code
  • Seperation of concerns
  • Better adherence to the Single Responsibility Principle
  • More flexible code that is much easier to both refactor and re-use

I personally find that DI encourages better code design in general. I think this is because it forces you to think more in terms of the interfaces between classes. The result is a lot more loosely-coupled code which is a very good thing.

I worked on VERY large project - multi-millions line of codes - and I never needed such level of indirection. I read both blog post and it doesn’t give a single example of an implementation that would becomes easier with this kind of DI. DI is great when you have two code-base that need to talk to each other, like server and a client.

Seriously? That’s the best reason to avoid Singleton?

I never use GameObject.Find or GameObject.FindObjectOfType. I use singleton, but I never have to “manage” them. All my “manager” are prefabs, and I could easily implement their behaviour as abstract base class. (Because we know how Unity love to serialize interface) My code never became a “big pile of crap” because of them.

I also have a registrable system that keep track of all the instance of specific types/subtypes I want.

I prefer subcomposition; breaking down my behaviour to its smallest bit and building it like legos. States of a StateMachine that are independent of the object owning the machine.

But above all, I prefer behaviours that can be changes in data. That I can change the whole game’s behaviour with one click in Unity, without changing any code. Abstraction trough data; composition by the designer.

The point of dependency-injection, from my point of view, is to change a service with ease - from the data, and right now, your example package doesn’t give me that possibility. What I’m trying to say is, your package should give an example of where DI is useful, and right now it isn’t.

Sounds like you’re using the Service Locator Pattern. Which is fine, and in my view the best alternative besides using a DI framework. There are downsides however. With SL, you end up having to deal with a lot more run time errors, since any method could ask the SL for an instance of a type that isn’t found. With DI, you can validate your object graph easily even before you run your application.

It’s also much more clear where the dependencies are using DI (you can just look at the constructor of your class to see them)

Also, if you write your code using SL, it is coupled to the implementation of SL. You cannot re-use that class without also using service locator. If you are using DI correctly then you actually don’t even need to be coupled to the dependency injection framework. You can re-use your classes by manually passing in all the dependencies into their constructor if you want.

There’s many other reasons as well to avoid SL in favour of DI (you can find a few more here: http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/)

Then it sounds like you would love DI! Using DI makes it incredibly easy to split up your code base into lots of tiny classes. This is because you don’t have to worry about passing dependencies around. Each class can just declare the services that it requires in its constructor and then focus specifically on the single thing that it is responsibile for.

I agree, data driven designs are great. So is data-oriented design (which is slightly different but related). I also admit that if you really embrace data-oriented design, that you can avoid relying on object oriented code (which in many cases conflicts with DOD). However, if you’re like me and have completely embraced the OOP philosophy then DI will make your life 1000x easier.

I actually think this is a common misunderstanding of dependency injection. The ability to swap one service for another is only one of the many benefits of DI.

I agree that the example project isn’t the best example, but that’s because it’s a small project. I literally threw together the sample in a weekend. If you were to take the sample application and try to build a several-month long project around it, THEN it would become much clearer how helpful it was to start out using a DI framework.

I’m happy to answer any more questions

How is performance when using DI over just doing it ?

I target mobile primarily so I would like to avoid any performance issues !

DI mainly affects start-up time when it builds the initial object graph. Though in some cases you also create object graphs at run time so may affect that as well. But even then it is usually sporadic (nothing per-frame).

It does use heavy C# reflection which is typically slow, but in Zenject a lot of this work is cached (using a C# reflection library called fasterflect) so it’s not bad. So it should only incur reflection costs once per class rather than once per instance.

… what?

IMO, frameworks like this should generally be avoided in game development.

They are often over architected and un-nessesarily, especially when you want lean fast code.

Ive seen streamlined apps become sluggish crud… but hey, youre giving it away free, so I cant fault you there.

I would like to hear more about the project(s) you are putting this into…

3 Likes

Thanks for sharing it! Looks great, and solves a lot of problems for my design. I’ll be using it on my project.

Zenject avoids costly reflection operations by making a trade-off between performance and memory. Zenject needs to process a class to find all the dependencies that it needs (which include its constructor parameters and any fields/properties marked with [Inject] attribute). But it only needs to do this once when it instantiates the first instance of said class (and thereafter uses the data from the cache). Make sense?

DI frameworks are a fantastic way to manage complexity in software and allow your software to scale well over time. It becomes less useful the simpler your problem domain is. Game development tends to be among some of the most complex software there is and so if anything, actually needs DI more than other kinds of software. Also, games tends to have requirements that are constantly changing (as you discover what works and what doesn’t) which means you need to have an extremely flexible codebase (which DI also helps with)

Can you elaborate on why you think DI should be avoided in game development? You mentioned speed considerations, but as I said above the performance hit is neglible in most cases.

I do agree that most DI frameworks are overly complicated, which is also something we tried to avoid with Zenject. I personally think it’s much simpler than most others you’ll find but as the author I’m biased

No problem :slight_smile: If you end up trying it and have any questions be sure to let me know (you can also submit requests/bugs on the github page)

I use dependency injection at work all the time, truly a paradigm shift that more developers should get into for large projects to at the very least separate concern.

I don’t have a use for this framework in Unity just yet, but I’ll keep it on my radar.

This would also need to be heavily tested in iOS as I’m betting some dependencies will trigger AOT errors.

Is there any game released with DI framework Zenject or StrangeIoC ?

Firstly thanks for framework. However looking at your ‘hello world’, first thing I notice is that it is far more difficult to read, so not really sure how feasible this would be.

@eventropy Thanks a lot for the framework, I’ve been testing it out. I’ve got the hang on setting up a RootContext and injecting into normal C# classes.

I now wanting to create some GameObjects within my scene with MonoBehaviours attached and inject into those MonoBehaviours, how does Zenject support this without me having to re-instantiate my GameObjects, as having GameObject placed within a scene prior to the application start is one of the core features of Unity.

Brilliant work on this framework -

How about:

container.Bind<YourGameObjectType>.To(yourGameObjectInstance)

I just opened the Asteroids sample scene and the first object under “CompositionRoot” is “Gui”. It has a MonoBehavior attached to it called “GuiHandler.” (So it qualifies as a monobehavior that “lives” in the scene.) This GuiHandler has field injection that looks like this (can’t do constructor injection on a Monobehavior):

public class GuiHandler : MonoBehaviour
{
    [Inject]
    public GameController _gameController;
...
}

The binding in the installer looks like this:

_container.Bind<GameController>().ToSingle();
1 Like

Just wanted to resurrect this thread to mention that Zenject has been updated to version 1.08, which includes, most notably, several more performance improvements. I believe it will satisfy the concerns such as those mentioned in this thread.

For anyone else interested I’ve answered this question in the google group here:
https://groups.google.com/forum/#!topic/zenject/OjJgz9p_XtM