Build Your Own Dependency Injection in less than 15 Minutes | Unity C#

Поделиться
HTML-код
  • Опубликовано: 8 сен 2024

Комментарии • 165

  • @git-amend
    @git-amend  8 месяцев назад +10

    Hi everyone! I hope you find constructing a lightweight Dependency Injection framework helpful! There are many ways to implement DI in Unity, and this is one I think is the easiest to digest. The solution to the challenge at the end of the video is included in the code repo (Injecting into Properties). Spend some time considering what features you would add to this implementation to make it bulletproof and more powerful.

  • @dabmaster6874
    @dabmaster6874 8 месяцев назад +33

    Your content brings a challenge to my learning journey. Your tutorials look more like software engineering than the usual Unity tutorials. I stumbled upon your state machine implementation and I was amazed. Subscribed and waiting for more and more content.

    • @git-amend
      @git-amend  8 месяцев назад +3

      Thank you so much! Cheers!

  • @nickr9160
    @nickr9160 8 месяцев назад +19

    Brilliant content, brilliant channel. Keep up the great work, it's a breath of fresh air seeing some upper-intermediate content, seems to be tricky content to find and yours is presented really concisely

    • @git-amend
      @git-amend  8 месяцев назад +2

      Much appreciated! Thank you!

  • @nexgen.graphics
    @nexgen.graphics 8 месяцев назад +5

    15 minutes of so much so much so much information. phew!!. I need to take a breath, watch it again and again to grasp this. A must need thing up my sleeve. Thanks for this tutorial.

    • @git-amend
      @git-amend  8 месяцев назад +1

      Glad you enjoyed it!

  • @endihidir2087
    @endihidir2087 8 месяцев назад +3

    I am using VContainer library for dependency injecton. This tutorial helped me understand how the system works behind the scenes. Thank you very much for this Awesome content 🙏🏼

    • @git-amend
      @git-amend  7 месяцев назад

      Great to hear!

  • @Runesun
    @Runesun 6 месяцев назад +2

    Your content is exactly what I've been hoping for as someone who's been doing tons of enterprise dev and just starting with Unity. Big big thank you! Also - why do I get the feeling that you've given more than your share of dev talks at either a local user group or something larger. You break things down and demonstrate extremely well. Been taking notes on that soft skill AND the game dev specific stuff.

    • @git-amend
      @git-amend  6 месяцев назад +1

      Thanks for the kind words! I don't give too many talks, except at work!

  • @TheMathias95
    @TheMathias95 8 месяцев назад +3

    As a software engineering getting into unity, these videoes are fantastic. From my experience it's very rare, even difficult to find basic programming principles from the software industry being covered in unity videoes.
    I've definitely been used to dependency injection and was baffled this is not a part of unity by standard.
    I really don't understand how the most common practices of developing scalable and modular code is not a priority amongst the avaerage Unity tutorial channel. I feel bad for beginners ending up in a world of issues due to bad design.
    Granted your videoes might be difficult from a beginners point of view, I think you a have pretty good balance, keeping the information relevant and understandable for the beginner.

    • @git-amend
      @git-amend  8 месяцев назад +1

      Thank you! Always encouraging to hear that kind of feedback. Cheers!

  • @jumpjumpdiegaming
    @jumpjumpdiegaming 8 месяцев назад +5

    As usual an amazing video with a lot of detail. I was wondering though, perhaps you could spend a few minutes at the beginning really unpacking what each concept is, for example, explaining what dependency injection really does/is. Otherwise, an amazing video! 😊

    • @git-amend
      @git-amend  8 месяцев назад

      Thanks for your comment! I'll keep that in mind!

    • @jumpjumpdiegaming
      @jumpjumpdiegaming 8 месяцев назад

      @@git-amend just would love to hear your thoughts and explanations as an experienced dev!

  • @angelomoro8430
    @angelomoro8430 Месяц назад

    This is a solid way to present Depency Injection in such a short time. I was struggling a bit to understand and use the DI systems in the market (like VContainer) used in a project I'm working on. After watching the video, and writing down the content presented in the video, I can say it works like a gem. Thank you so much!

    • @git-amend
      @git-amend  Месяц назад

      You're welcome, thanks for the comment!

  • @KeyboardKrieger
    @KeyboardKrieger 8 месяцев назад +1

    This is just really good stuff. As a software engineer i like this advanced stuff. It's not the standard in unity tutorial world

    • @git-amend
      @git-amend  8 месяцев назад +1

      Thanks, I appreciate that!

  • @risingforce9648
    @risingforce9648 8 месяцев назад +3

    Please more videoa baout DI . Thanks , this is a gem video...I need a little more touch to understand ..but it is very cool!!!

    • @git-amend
      @git-amend  8 месяцев назад

      Thank you, I will

    • @feildpaint
      @feildpaint 8 месяцев назад +1

      ​@@git-amend As a more novice programmer, I'm also having some difficulty understanding the uses of this framework. I think seeing concrete examples during runtime with things actually happening in a game would help a lot. Thanks for the great video anyways!

    • @risingforce9648
      @risingforce9648 8 месяцев назад

      it is exccellent and you use tecnical glosary, such as service, provider, inyector , etc, I should really try to make a cheat sheet in my block to understand that glosary..related to my curiosity to wikipedia and some other reading online.... it is hard and I still learning to implement in unity ,however thank you so much for the purpose of this video, I think this concept is a must for become a good programmer and stop the godot migrations.

  • @mrcallum1995
    @mrcallum1995 8 месяцев назад +2

    Love this series of tutorials! I wanted to say I was expecting you to build upon your service locator from last video to build this system, since that and DI are opposite sides of the same coin. That system was super flexible and allowed for scoping. Either way this is an interesting way of providing services through attributes, instead of the usual registration / binding workflow found in Zenject or Microsoft DI. Nice one!

    • @Utamaru56
      @Utamaru56 8 месяцев назад

      Looks pretty similar to Zenject though because IDependencyProvider is basically an installer

    • @git-amend
      @git-amend  8 месяцев назад +2

      Thanks! It would be nice to eventually build a system that can handle all the best features of both implementations and then include some graph theory to validate all dependencies too. That gave me an idea for a future video! Cheers!

  • @cheesecakenl1980
    @cheesecakenl1980 8 месяцев назад +1

    Ah yes... Short and concise. Right up my alley.

  • @ekekw930
    @ekekw930 8 месяцев назад +1

    Im always looking forward to your videos on Sunday!

    • @git-amend
      @git-amend  8 месяцев назад +1

      Yay! Thank you!

  • @MafiaSniper
    @MafiaSniper 4 месяца назад

    Great video!
    Although too difficult for me😌I think I should start with the theoretical side first.

    • @git-amend
      @git-amend  4 месяца назад +1

      Sure! One step at a time!

  • @trex6867
    @trex6867 7 месяцев назад +3

    Please record more detailed video about dependency injection and unit testing

  • @user-kp4by9cg2e
    @user-kp4by9cg2e 29 дней назад

    Im really thank you for your post...
    is really really helpful to me

    • @git-amend
      @git-amend  29 дней назад

      You are most welcome

  • @PetersExcapades
    @PetersExcapades 5 месяцев назад

    i strive to be as good as you one day good sir, i really like how you architect your code!

    • @git-amend
      @git-amend  5 месяцев назад

      I appreciate that!

  • @devphil0
    @devphil0 8 месяцев назад +1

    Great stuff as always. A few things I wanna say: A comment mentioned combinding service locators and this DI framework so I'm very interested to see what you'd come up with for that.
    I see other DI frameworks use lifecycle integration for Update and so on, so I wonder how easy it would be to integrate into this framework? Probably just a matter of defining interfaces for such services and making sure to instantiate and resolve them, I assume. Similar to how VContainer does it.
    And lastly, a little critique on your editing, i would find it great if you could linger on the code you just wrote a little bit longer. Sometimes I find myself confused where a debug statement came from because the code was shown for like 1 second. I know I can pause and return but it would improve the overall clarity of the video.

    • @devphil0
      @devphil0 8 месяцев назад

      And another thing I will probably do myself is build an instantiation system that automatically resolves dependencies on a new prefab.

    • @devphil0
      @devphil0 8 месяцев назад

      And ANOTHER thing i think would be pretty good too, since I've been pretty bootstrapping pilled lately, I would probably modify the system to run either on subsystem registration or on scene loading to make sure it all happens before any Awake call. Changing execution order works too, but why do that when you can make sure that 100% of the time your system will run before anything else.

    • @git-amend
      @git-amend  8 месяцев назад +5

      Thanks for the comments. Implementing lifecycle is not too hard to do in both the Service Locator and this DI system, and I would do it with interfaces as well. There will likely be more videos on DI coming up to dive a bit deeper into these areas, and others that come up in comments. Cheers!

  • @yashaswiification
    @yashaswiification 8 месяцев назад

    Thank you!! For teaching us

  • @ugurkarabulut8598
    @ugurkarabulut8598 8 месяцев назад

    I've just learned zenject and u post this :D

    • @git-amend
      @git-amend  8 месяцев назад

      Haha.. well congrats! Most people find Zenject a bit overwhelming at first, so that's a big accomplishment! This must seem trivial!

  • @emz6133
    @emz6133 4 дня назад

    What would be your go-to approach for dependency management in Unity? Building your own lightweight DI framework? So far I've seen only you suggest that (I'm not saying it's not a good solution). For MonoBehaviours I use serialized fields, but I don't know what to use for standard C# classes. And I assume if I pick one approach for standard classes I should use it in MBs also and drop serialized fields (for providing dependencies) completely, right? What are my options? There is Service Locator, but people generally don't recommend it. Concerning DI frameworks, Jason Weimann and Jason Storey say that you should only use them if your dependencies become too complex and you cannot manage them on your own. I'm building a mobile MOBA game, so that would be a medium or large size project, I'm not sure how to classify it.

    • @git-amend
      @git-amend  4 дня назад

      I would say that even if you don't introduce DI from the start you should program with the principle of Dependency Inversion in mind so that your code is as loosely coupled as possible. In Unity it's almost impossible to have completely decoupled code due to heavy use of Serialized Fields and so on, but where possible you should be using appropriate levels of abstraction and supplying dependencies to the classes that need them in some fashion. If you keep the D in SOLID in mind while you are programming, and you find later that you need to use a DI Framework or a Service Locator, it will be easier to introduce than if you are creating your dependencies inside the class that depends on them. That's harder to do with MonoBehaviours because you can't have a ctor, but with plain C# classes it should always be the case. For me personally, I would use some form of inversion of control from the start, either my own solution on a small project, or on a bigger project I would probably choose either Reflex or Sisus Init Args from the Asset Store.

  • @rutchjohnson
    @rutchjohnson 8 месяцев назад

    I will say, you have some great content. But I'm not sure who these videos are for. One question that I have is why should I use this system and what real world problem does this solve/make easier for devs? I look for this question to be answered at the beginning of every tutorial video I watch. It sets the tone and direction for the rest of video. Thanks for the great content! :)

    • @git-amend
      @git-amend  8 месяцев назад +2

      Thanks for your comment. The inversion of your dependencies (aka Inversion of Control) is a key part of object oriented programming and of course is the D in SOLID.
      Using a Dependency Injection system or a Service Locator are ways to achieve Dependency Inversion where your dependencies are not tightly coupled to the objects and systems which depend on them, making it easier to manage, extend, and test large and complex Unity projects.
      If you haven't yet encountered a situation where you needed to refactor or scale up a project significantly, the benefits of this system might not be immediately apparent, but they become invaluable in larger, more complex development scenarios where tightly-coupling all your game objects and systems together can lead to a cascade of problems if one part needs to change.
      If time permits, I'll create a real world example before the next video on this topic. Cheers!

    • @rutchjohnson
      @rutchjohnson 8 месяцев назад

      @@git-amend oh nice! Thanks for the explanation. Yeah I think I wouldn’t be alone in this but up front stating here is the value in this xyz concept is important so that I have a reason to use what you are teaching us. Again love your teaching style and expanding my knowledge of Unity and C# :)

    • @sisus_co
      @sisus_co 8 месяцев назад +4

      Another way to understand the benefits of using a DI framework in Unity, is that it can pick up where serialized field-based DI stops working:
      1. Cross-scene references.
      2. Interface support.
      3. Injecting dependencies manually in code (essential for unit tests).
      4. Dynamic values (e.g. inject different objects based on current platform).
      5. Easily swapping a service to a different one for all components in all scenes and prefabs.

  • @TheKr0ckeR
    @TheKr0ckeR 4 месяца назад

    re-watched your video and completely understood how DI framework works. Thanks a lot for that. What makes me think is which classes should we provide? Like Manager classes, or even player? I think its all about providing super-classes or "single" classes. Are there any scenarios where we provide "an enemy instance"? I really got how this framework works, but i am confused about what to provide. For example a wave controller class where it spawns - despawns to get information if wave spawn ended? And a game state class where it controls the game state itself. Are those a good example to provide so that others can easily react by game state, or wave endings like UI etc.

    • @git-amend
      @git-amend  4 месяца назад +1

      A good way to think about that is to consider classes that are dependencies for another class. So, if your AI Agent depends on a Blackboard, you can provide that using Inversion of Control for example - either Dependency Injection or a Service Locator. Whenever one class depends on another class that is a 'system' (not some static creature or item in your game world) you should attempt to provide it in a decoupled manner, and you should implement either a base abstract class for it or an interface. This way, if you were to completely change the Blackboard implementation, the classes that use it don't have to change.

  • @vigscodes
    @vigscodes 8 месяцев назад

    Great video thanks for sharing!

    • @git-amend
      @git-amend  8 месяцев назад

      Thank you! You're welcome!

  • @kevin41307
    @kevin41307 7 месяцев назад

    mind blowing content!!

  • @mask7376
    @mask7376 6 месяцев назад

    Injection or Singleton. Which one ?

  • @okhalo_dev
    @okhalo_dev 8 месяцев назад +1

    Thank you for the video!
    I have a question: will the 'auto' injection only occur when the game starts (upon the awakening of the injector singleton)? So, are injectables only fed if they are present in the initial open scene at the beginning? Why not use something like "[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] or scene loaded event" to iterate each time a scene is opened? Also, what happens with runtime-instantiated objects? Should I 'manually' call 'Inject(instance obj)' on the singleton, passing it as an argument in my factory or use Service Locator?
    (I'm using additive scenes system and can't add an injector singleton to each scenes)

    • @git-amend
      @git-amend  8 месяцев назад +2

      Thank you! Glad you like the video. To answer your questions: Yes, this injection system runs when the Scene starts for all injectables present in the scene at that time. You can perform injection on demand from within the scene for objects created at runtime, just pass 'this' into the Inject method.
      Using RuntimeInitializeOnLoadMethod is a viable choice - but it also has limitations. This attribute is for when the runtime is starting up and loading the first scene - it does not automatically trigger methods to run again when additional scenes are loaded additively. Keep in mind that going this route means that you cannot execute any code in the scene before Injection happens - for example, you might want to perform some logic and validation in the Awake methods of various providers, and move the injection to be performed during the Injector's Start method.
      If you can't have an Injector present in each scene due to a limitation of your additive scene system, using the SceneManager.sceneLoaded event may be your best option.

  • @Cloud-Yo
    @Cloud-Yo 6 месяцев назад

    This is awesome stuff...now, what kind of overhead does all this have if you were to spam injection over a larger project? Either way, I got to see how little baby attributes are born...nature is amazing.

    • @git-amend
      @git-amend  6 месяцев назад +1

      There will definitely be some startup cost which would scale based on size; on a bigger project you might want to consider a more powerful DI solution like Zenject. Glad you liked it!

    • @Cloud-Yo
      @Cloud-Yo 6 месяцев назад

      @@git-amend Got it, I think its called Extenject now after 2020. Thanks to this video I feel better prepared to tackle that tool. p.s. got properties working as well. Thanks again!

  • @user-dd2yx9ze6x
    @user-dd2yx9ze6x 5 месяцев назад

    Thanks for this tutorial, but don't compress it to too short, slow down so we won't need to pasued often.

  • @friedcrumpets
    @friedcrumpets 8 месяцев назад

    I was looking into building one of these a while ago but when it came down to it the reflection and attribute tagging put me off and leaned me towards a ServiceLocator allowing monobehaviours to grab dependencies on Awake. With unity specifically it feels more logical as with DI it usually requires a bit more of a standardised framework to pull off. If not everybody on the team is familiar the DI can easily get thrown out of the window quickly.
    Are there any performance drawbacks to be aware of in using this?
    Brilliant video as always, really great to see this kind of thing covered in such an easily digestible way. Keep them coming :D

    • @git-amend
      @git-amend  8 месяцев назад +2

      There will always be some overhead when using reflection, and while it's worth noting that Unity's performance with reflection has improved over time, the more classes you have to search through in this system, the more of an impact it will have. You can optimize this of course, and one way would be to gather services used together into an abstract factory instead of injecting them all seperately. You can also add a bit more funcitonality to this system and begin to cache services for different scopes, similar to what we did with the Service Locator so that we have global and scene level dependencies. This will be the topic of an upcoming video.
      Other considerations - right now the system is only looking for dependencies provided from MonoBehaviours. It also does not perform any validation - you might want to apply some graph theory to verify completeness.
      Like all systems, there is always room for improvement, and we'll continue to dive into these kinds of things. Thanks for your comment!

  • @muhammadzubairirshad6724
    @muhammadzubairirshad6724 8 месяцев назад

    Just Amazing

  • @unitydev457
    @unitydev457 4 месяца назад

    Hi, this is an incredible tutorial! I had two questions. first is a syntax i was unsure of:
    at around 9:30 you did something that im a bit unclear on. line 65: var resolvedInstances = requiredParameters.Select(Resolve).ToArray();
    How does Resolve know the type if its not passed in?
    Does Linq's Select pass the type of requiredParameters as if you called Resolve(requiredParameters)?
    2) Am I understanding correctly that in this implementation all providers and dependencies need to exist as game objects in scene at start? The inject method only gets called once right? So this wouldn't account for game objects instantiated during runtime? Or did I misunderstand

    • @git-amend
      @git-amend  4 месяца назад

      Thanks! To directly answer your first question: Yes, LINQ's Select method passes each element (Type in this case) of requiredParameters to the Resolve function, effectively behaving as if you called Resolve on each individual Type contained in requiredParameters. This allows the Resolve method to attempt to fetch an instance of each type from the registry.
      For your 2nd question, yes this system is meant to exist in your game on game objects and runs only one time, so it's meant for injection on things that exist from the beginning of your game. If you need more power than that, you can either inject factories into things like spawners so that you can use them when instantiating new objects, or you can feel free to fork and extend the library as you see fit... or you might feel comfortable enough to use a more complex and powerful 3rd party framework.

    • @unitydev457
      @unitydev457 4 месяца назад

      @@git-amend Thanks for the answers! Ive been working on my own dependency injection system and still haven't quite sorted out how I want to handle runtime dependencies but it seems like factories are a really solid option to get around the no constructor issue.

  • @rofu8096
    @rofu8096 8 месяцев назад

    My gratitude is beyond words. Thank you very much for all the information you provided.

    • @git-amend
      @git-amend  8 месяцев назад +1

      You are very welcome

  • @sagrgywejhxcvx
    @sagrgywejhxcvx 28 дней назад

    I use a service locator and it works perfect, why is DI better?

    • @git-amend
      @git-amend  28 дней назад

      Maybe watch the video about D in Solid. The short answer is that with a Service Locator, you will always be coupled to the Service Locator. With DI, your classes are not coupled to anything. They are both good options though in my opinion. ruclips.net/video/JSqE4C7ZZos/видео.html

  • @gladiko2364
    @gladiko2364 8 месяцев назад +1

    That was cool, b-but where/when would you ACTUALLY use this?

    • @git-amend
      @git-amend  8 месяцев назад +1

      You would use it in situations where different components or systems in your Unity project need to share or use common services or objects without tightly coupling them together. It reduces the dependencies between components, leading to a more decoupled architecture.
      An example would be injecting references to a localization service into various components. You might have 20 game objects that need to call the localizationService.translate() method, so they all must keep a reference to this service. With DI, you don't tightly couple game objects to their dependencies by dragging and dropping a reference to this service in every game object, instead it's injected where needed.
      You would also use it when testing, you could inject a service that always returns the same result so that you aren't testing end-to-end, you are testing just the component under test.

    • @laserbean00001
      @laserbean00001 8 месяцев назад

      @@git-amend This is really confusing. Why don't you just use a static class and static method to run those stuff instead of the object reference?

  • @lukass1604
    @lukass1604 8 месяцев назад

    Keep up the videos👍

  • @mongreldesigns9195
    @mongreldesigns9195 8 месяцев назад

    I am learning so much from your tutorials, thank you.
    I do have one (possibly stupid) question, I can't for the life of me figure out where the attributes are assigned.... how does this...
    public sealed class InjectAttribute : Attribute { }
    Get identified as [Inject]

    • @git-amend
      @git-amend  8 месяцев назад +2

      That is a very reasonable question, one that I asked myself long ago. Actually I'm surprised nobody else has asked that yet. In C#, attributes are defined using their names followed by the word "Attribute".
      When you define public sealed class InjectAttribute : Attribute { }, you can use it as [Inject] in your code. This is a shorthand provided by C#, where the "Attribute" suffix can be omitted when you're using the attribute.
      You can also use the full name if you wanted to like [InjectAttribute] - both ways are correct and functionally equivalent.

    • @mongreldesigns9195
      @mongreldesigns9195 8 месяцев назад +1

      @@git-amend That is where my head was but i could not find anything to validate the theory, probably because I thought it was a unity thing.
      Thank you again, your videos are just above where I feel I am at, making them perfect to progress!

  • @Andrew-pd2ci
    @Andrew-pd2ci 8 месяцев назад

    Hey mate, sorry for bothering you. Can I somehow have a chat with you, I kinda need help with a specific sort of stuff plus I have a sort of a deal for you. At least will be nice to have a little talk. I can't find a way to message you directly or your email :(. I will tell you about myself(spoiler, I am a game dev) and what I am working on atm.
    Btw, thanx for your content, the most professional coding content about game dev as a topic on RUclips, thank you for the high-quality content

    • @git-amend
      @git-amend  8 месяцев назад

      At this time, I don't have the bandwidth for chats per-se but if you have a question about something you don't want to post here, you can message me on Twitter - link is in the description.

    • @Andrew-pd2ci
      @Andrew-pd2ci 8 месяцев назад

      @@git-amend
      I tried to, but idk why I am not allowed to text anbd there....
      Will be okay to chat under that comment then ?

    • @adammyhre
      @adammyhre 8 месяцев назад

      @@Andrew-pd2ci Settings prevent DMs until you get a follow back. Try again.

  • @user-cl8lf1wm8b
    @user-cl8lf1wm8b 4 месяца назад

    what are downsides of DI in your opinion? in a context of unity I mean

    • @git-amend
      @git-amend  4 месяца назад +1

      It can lead to increased complexity, potentially complicate debugging and potentially affecting runtime efficiency if you were to start injecting beyond game start up. These are all things that can be mitigated, however.

  • @endihidir2087
    @endihidir2087 7 месяцев назад

    There's something I'm curious about. Why did you choose to make the FindMonoBehaviours() and IsInjectable() methods static? Because they work even when they are not static?

    • @git-amend
      @git-amend  7 месяцев назад

      Generally speaking, it is a best practice to mark public and private methods that do not require state as 'static', and your IDE may even hint you to do this. There are a few reasons for this; one is that it makes your code self-documenting - it indicates to future you or anyone else reading your code that this method does not use any instance members and is pure utility. There is also a small compile time benefit in C# which you can read about here: stackoverflow.com/questions/135020/advantages-to-using-private-static-methods

    • @endihidir2087
      @endihidir2087 7 месяцев назад

      @@git-amend I understand, thank you very much for the source. In general, it is recommended in some places not to use static structures unless absolutely necessary, for many reasons, such as memory consumption (especially for mobile games), lifetime, difficulty in testing, etc. That's why I'm a bit confused, to be honest.

  • @doancatphu6912
    @doancatphu6912 5 месяцев назад

    nice content. I wanna ask that can we have only one singleton manager script managing others manager and combining with dependency injection to make our project become maintainable and scalable. If i dont use singleton in my project, what alternatives will be the best. Thanks!

    • @git-amend
      @git-amend  5 месяцев назад +1

      Technically that is possible, but it's often not practical. The biggest issue with this is that having just one singleton managing all other systems becomes a bottleneck, both in terms of performance and maintainability, if not carefully managed. It is in a way introducing a new form of tight coupling because every module in your program would be tightly coupled to this singleton object. I would lean towards keeping the project modular instead of routing through one god-object. On the other hand, there are some advantages to injecting a singleton, such as breaking the dependency on the singleton using injection, which makes your code much more testable.

    • @doancatphu6912
      @doancatphu6912 5 месяцев назад

      @@git-amend cause i found out that it is not good when you abuse singleton too much in your project. I asked others and was told to manage managers in only one singleton. So in sum up, i can combine singleton and DI to make less dependency, right?

  • @lost.250
    @lost.250 7 месяцев назад

    As far as I can see the system only injects at Awake, what about classes that are created dynamically?

    • @git-amend
      @git-amend  7 месяцев назад

      That's correct - can only fit so much into 15 minutes! Feel free to fork the library and add more functionality. Perhaps, if enough people ask, I will make a video about extending this in the future.

    • @lost.250
      @lost.250 7 месяцев назад

      @@git-amend It would be great to see it! Keep up the good work, I really appreciate your videos :p

    • @dawidkubiak5642
      @dawidkubiak5642 6 месяцев назад

      @@git-amend
      Great video! Extending your DI system to support dynamically created classes would be incredibly beneficial for many of us working with Unity.
      Considering the interest it has already sparked, a follow-up tutorial could be highly valuable for the community.
      Looking forward to possibly seeing more on this topic!

  • @oswaldcobblepot764
    @oswaldcobblepot764 8 месяцев назад

    I wish i had this 5 years ago :D

    • @git-amend
      @git-amend  8 месяцев назад +1

      I know that feeling!

  • @h.y-chen
    @h.y-chen 3 месяца назад

    old dotnet guy but new to unity here, after I learn the basic of Unity ,the first thing I do is find a way to use DI in unity since it make things way more easier, then I come across this video , but since the reflection is expansive so if build it my self it become nasty with lot expression trees or IL generation , I'm curious if you have attempted to integrate Microsoft.Extensions.DependencyInjection with Unity? The video made it seem achievable, and I'm interested to know if you already tried it

    • @git-amend
      @git-amend  3 месяца назад +1

      I have not tried that - but to be honest it sounds very interesting. If you do look into it, please let me know, I'd love to see what you come up with!

    • @h.y-chen
      @h.y-chen 3 месяца назад

      @@git-amend I'll try but need look more deep into UnityEngine first , the DI impl in your video it get all gameobject when excuting the script , so I guess it won't work if create game object dynamiclly?

    • @git-amend
      @git-amend  3 месяца назад

      @@h.y-chen That's correct, all dependencies in this 'lite' system are expected to be present at the start. A potential workaround is create a Factory and make that the dependency that will then create GOs at runtime. Otherwise you may need to look into some kind of registration system and verify a dependency graph too. I added a few improvements in the following video, but nothing quite that complex.

  • @TheKr0ckeR
    @TheKr0ckeR 8 месяцев назад

    Great guide, I always have a pre-judge against DI in Unity. How often do you use DI framework in your projects? I find myself pretty confused against changing the code structure and putting DI Third party framework on top of everything, like WContainer. I feel like I am fightining with unity when i use DI framework

    • @git-amend
      @git-amend  8 месяцев назад +2

      I can relate to that, especially if you are trying to introduce DI after you've already been developing your project for a while. For me, I do not use it in every project. It's more important to adhere to the Dependency Inversion principle than how you go about it. Some coupling in Unity is unavoidable of course. In many cases, just programming with the concept of Dependency Inversion in mind is enough to save yourself a lot of grief in the long run. For me personally, it would be a choice to use a DI framework (or a Service Locator) or not from the start of the project rather than trying to shoehorn it in later on.

    • @TheKr0ckeR
      @TheKr0ckeR 8 месяцев назад +1

      @@git-amend Great answer. Thanks man. Still DI is not in my top 3 in Unity :D But your video really made me understand how to achieve DI without third party.

    • @sisus_co
      @sisus_co 8 месяцев назад +1

      In my experience the trick to making a DI framework not feel like it's fighting against Unity is to spend some effort to integrate it well with the Inspector. Just like with serialized fields, it should be easy to locate injected services just by looking at the Inspector, and if you want to replace one, you should be able to just drag-and-drop some other instance in.
      I think that after this change, most of the usual complaints that people have about DI frameworks in Unity become non-issues.

    • @TheKr0ckeR
      @TheKr0ckeR 4 месяца назад

      @@git-amend What is your most-preferred communication type between high-level systems like GameState, controller etc. Singletons, Service Locators or DI like zenject etc? I have started a new game where i have game controller which holds the data for "Game status like pregame, warmup, and stuff." Player will be ready and inform about game state, so that spawner can start spawning by that delegate. To communicate between those, how would you approach to that solution in best practise scaleable way?
      1- Player will click ready button
      2- Game state should react to that by making the game status/ready.
      3- After game is ready, spawner will spawn the wave.
      So how would you communicate between those? My game is full of this type of communications and i dont know how to approach to that as best case.
      My approach would be,
      Player will have a delegate OnReady, and will call it from button.
      Game state serializes the player as a field, and subscribe to ready event.
      Zombie Spawner will somehow need to know game state, and subscribe to OnGameStateChange event, but singletons? Service locators? DI? Or game state will also know about Zombie Spawner and will simply call, spawner.StartWave(); or another, zombie spawner will know about gameState as serializeField.. I want to choose between them but i cant decide. I want to make it as a best practise and follow along.
      I am really wondering your approach here.

    • @git-amend
      @git-amend  4 месяца назад +1

      @@TheKr0ckeR I would use an Event Bus to handle the situation you are describing: multiple disparate systems need to coordinate based on specific events initiated by the Player. This is especially useful if you are working with multiple scenes, but a good solution for any project.

  • @user-zs9cl2to3x
    @user-zs9cl2to3x 8 месяцев назад

    The only question I was chasing during the whole video is what's the purpose of all that stuff? What are the benefits?

    • @git-amend
      @git-amend  8 месяцев назад

      Thanks for your comment. A Dependency Injection framework is one way of fulfilling the 'D' in SOLID. It's purpose is to decrease the amount of tight coupling between your systems so that if you need to change one system you don't have to refactor everything that depends on it, or serialize any references to that system - instead the system is provided as needed, and if you program to interfaces you can simply provide a different system without changing any other code in your project.
      If time permits, I'll include a real-world example in the next video to further illustrate this concept.

    • @user-zs9cl2to3x
      @user-zs9cl2to3x 8 месяцев назад

      @@git-amend got it. Thank You for clarification. Indeed it would be great to see real world example.

  • @ZombieChicken-X
    @ZombieChicken-X 6 месяцев назад

    Hi I'm new to architecture coding (I think that's sorta what this is?) I'm trying to organize my projects more instead of having 1 singleton with references to all my classes. Does it make sense to use dependency injection for things like manager classes? For example if I have a MonoBehaviour class that handles a majority of the UI or a player animation handler, can those be services injected into other scripts?

    • @ZombieChicken-X
      @ZombieChicken-X 6 месяцев назад

      Im thinking this could work? Id be able to inject PlayerInputHandler and PlayerAnimationHandler into my main Player class on an initialization method, am I understanding this correct or is there a better approach to what I need

    • @git-amend
      @git-amend  6 месяцев назад +1

      That's the general idea. Dependency Injection and Service Locator, are ways to achieve Dependency Inversion - which is to supply the dependencies for a given class at runtime without tightly coupling the class to the dependencies and/or without having to create the dependencies inside the class that requires them.

    • @ZombieChicken-X
      @ZombieChicken-X 6 месяцев назад

      Thanks man I really like your videos and am binge learning with them. Btw what do you use to edit them?@@git-amend

  • @Typtick
    @Typtick 8 месяцев назад

    I have a problem. If we have IEnvironmentSystem as an interface and create 2 different classes that implements this interface and both of these classes want to provide the injection content from itself with the Provide Attribute. Registery will have two same type Key and cause an exception.
    Is that intentionally planned in the video like is it something you expect us to figure out or am I having a problem?

    • @git-amend
      @git-amend  8 месяцев назад

      This is intentional - this system is just an MVP. Feel free to extend it as much as you like. If you don't want to extend it to directly support that type of behaviour, you could provide a factory instead and let the classes that depend on the interface type call the appropriate factory method (or one factory method with a param) to get the correct concrete type. So EnvironmentFactory could support multiple IEnvironmentSystem implementations.

    • @Typtick
      @Typtick 8 месяцев назад

      @@git-amend
      Thank you for your answer!
      I've been on Unity for 2 years and seen countless of tutorials but yours are super under-rated. Especially it helps me out since these patterns and architectural approach was quite lacking on my end for Unity. Please feed us with the content!

  • @LuRybz
    @LuRybz 8 месяцев назад

    i really like the content that you bring, your thumbnails, titles are really attractive to me but I feel that inside the video the content is too abstract and hard to follow.
    Often there is plenty of complex systems already in the code, lots of presumptions and knowledge before and there is lack of analogies.
    I can follow your videos but I feel there is a lot of space for improvement and this can bring more visibility to your channel.
    I hope this sounds to you like a constructive feedback and not an complaining.
    Thank you for sharing your knowledge.

    • @git-amend
      @git-amend  8 месяцев назад

      Thanks for your comments, your feedback is always welcome.

  • @OrekiBurd
    @OrekiBurd 8 месяцев назад

    Im kind of a beginner, trying to understand the video. Whats k_bindingFlags do in 4:43 actually binding flags in general

    • @git-amend
      @git-amend  8 месяцев назад

      That's a great question! BindingFlags in C# are used to define how reflection searches for members (methods, fields, etc.) of a class. In the context of this example, the combination of these flags specifies that the reflection should look for both public and non-public instance members. So, in this video, when reflection is used with these BindingFlags, it will scan through all instance members (fields, methods, etc) of a given class (in this case each MonoBehaviour we have found in the scene), regardless of their access modifiers (public or non-public).
      learn.microsoft.com/en-us/dotnet/api/system.reflection.bindingflags?view=net-8.0

  • @wisemiceclique4498
    @wisemiceclique4498 8 месяцев назад

    Ok, so what if I want to inject something in other scene. Let’s say that we have classB component in the next scene. Just adding the attribute won’t work in this case. What’s the best way to manage this?

    • @git-amend
      @git-amend  8 месяцев назад +1

      This Injector component works on a per scene basis. In this implementation it handles the dependencies for the scene that it belongs to. Unless you are trying to persist it across multiple scenes with a [DontDestroyOnLoad] attribute, it will work for every scene you put it into by finding and then injecting all the dependencies that have been provided in that scene.
      In the next video we are going to start talking about scope and make this system more powerful so that it can handle dependencies that need to exist across multiple scenes.

    • @redboss5429
      @redboss5429 8 месяцев назад

      Would like to use this as replacement for scriptsble object singletons so i can have it across scenes! Awaiting a part 2🎉

  • @ekekw930
    @ekekw930 8 месяцев назад

    Does this remove the need of Singletons? I have a save and load system that is implemented as a singleton with DontDestroyOnLoad. Can I refactor this to a service that will be used by DI? How does it handle different scenes?

    • @git-amend
      @git-amend  8 месяцев назад +2

      DI doesn't necessarily remove the need for singletons, but the short answer is that generally yes, you probably can refactor your singleton save and load system into a service for use with Dependency Injection (DI). You mention that your system requires it to be scene independent. This particular implementation of DI is very simple, so you would want to look at combining the features used in either the Service Locator video or the EventBus video to bootstrap a class that would handle your injections in a more powerful way, including on a per scene basis or at a global level. As mentioned in a few other comments, this will be the topic of a future video, so stay tuned!

    • @ekekw930
      @ekekw930 8 месяцев назад

      @@git-amend Thank you for the answer! What I currently did to "solve" this was to change the Singleton class to use the DontDestroyOnLoad method. I then added all the needed Provider scripts to my prefab that also has the Injector script. This way they are all persistent over multiple scenes. Not sure if I am happy with this solution and if it is even a good one, any thoughts?

    • @ekekw930
      @ekekw930 8 месяцев назад

      @@git-amend Also you mention a SceneLoader video but I cannot seem to find it?

    • @git-amend
      @git-amend  8 месяцев назад +2

      @@ekekw930 One thing that comes to mind is that you may need some kind of system to provide and inject services that are required after your Injector class runs it's Awake method for the first time - because it won't be run again in your scenario. In Scene 2, if you have some new dependency that didn't exist in Scene 1, it won't be found. This is why you might need to upgrade this system in the same manner as the Service Locator video which could find all your Providers in all scenes and register them on a per scene basis. You could then inject dependencies on scene load, and also maintain global dependencies throughout such as a save/load system. We'll get into this in a future video, but feel free to try it yourself - just make sure you commit your work first! 😜

    • @git-amend
      @git-amend  8 месяцев назад +1

      ​@@ekekw930 Sry.. brain not working - I meant Service Locator - ruclips.net/video/D4r5EyYQvwY/видео.html

  • @nuin9937
    @nuin9937 8 месяцев назад

    Whats your workflow for having UI decoupled?

    • @git-amend
      @git-amend  8 месяцев назад

      It depends. In many cases where you just want to display information, like a HUD, then Scriptable Objects make great Mediators. For example, values to be displayed for a Player's health and mana can be stored in Scriptable Objects and read by any components that need them. This simple approach is sufficient for many games as far as UI goes. However, many projects require a bit more interaction, and for that I would use either an Event Channel or an EventBus. There are videos on both those topics on this channel. Because UI varies from project to project, there is no real one size fits all solution.

    • @nuin9937
      @nuin9937 8 месяцев назад

      @@git-amend yes actually I have been using scriptable objects, but I keep thinking about a situation where for example you have a variable amount of entities that need UI, like if you decide to make your game multiplayer, then the approach wont work. Ill check out the things you mentioned, thank you

  • @laserbean00001
    @laserbean00001 8 месяцев назад

    Okay. From what i understand, instead of creating a class instance each time, the provider creates one and injects it into anything that needs it. It really seems like this can be solved with a static class.

    • @git-amend
      @git-amend  8 месяцев назад +5

      The reason people choose DI over static classes is that calling static methods creates tight coupling with the classes that call them. In contrast, DI promotes loose coupling by allowing you to interchange implementations without altering the dependent code.

    • @laserbean00001
      @laserbean00001 8 месяцев назад +3

      @@git-amend it would be great if you could give us some real examples where using this is better than the other methods. Cause this looks like a lot to set up.
      (Currently in my unity journey, i've learnt about all sorts of programming patterns with the most recent one before this vid being the observer pattern. So I really want to make sure i learn things correctly.)

  • @jacobs.7925
    @jacobs.7925 8 месяцев назад

    Any specific reason to call singleton's namespace Malevolent? 😂😅

    • @git-amend
      @git-amend  8 месяцев назад +1

      Top secret! lol

  • @retrospective9425
    @retrospective9425 8 месяцев назад

    Hi there....is there any email from you? Any way to make any contact?

    • @git-amend
      @git-amend  8 месяцев назад

      You can DM me on Twitter, link is in the description.

  • @xopabyteh
    @xopabyteh 8 месяцев назад

    Although I feel that DI is an excellent design pattern, i feel like it is an overhead for game making, as it's kinda performance heavy.

    • @git-amend
      @git-amend  8 месяцев назад

      I agree, it's good to understand and suitable for some projects, but overkill for some.

    • @nasterofpuppets
      @nasterofpuppets 8 месяцев назад

      There are many ways to do DI, including using serialized fields, pure DI and source generators, so using the design pattern is not necessarily performance heavy at all. In fact, converting runtime GetComponent calls to serialized fields is a common performance *optimization* tactic in Unity :)

  • @edward3190
    @edward3190 8 месяцев назад

    This seems like Singleton pattern. Instead of [Inject] ServiceA, [provide] ServiceA, why not ServiceA.GetInstance, ServiceA.SetInstance, you can drag and drop different ServiceA between active and inactive hierarchy, so that only the one in active hierarchy would SetInstance as itself during OnEnable().

    • @git-amend
      @git-amend  8 месяцев назад +1

      Thanks for your question! Using an instanced singleton for dependencies creates tight coupling because the game object directly relies on a specific, concrete implementation. While you aren't coupled directly to the service, you still require a reference to the singleton in order to call it's public Get and Set methods. A DI system removes this coupling.

  • @rechnight
    @rechnight 2 месяца назад

    Maybe something I'd change is instead of injecting everything from the Injector on Awake, is to have the MonoBehaviours call the Injector on themselves.

    • @git-amend
      @git-amend  2 месяца назад +1

      I don't think you could call that an Injector anymore. If MonoBehaviours start calling the Injector on themselves, it shifts the responsibility of dependency management back to the MonoBehaviours. What you are describing sounds a bit more like a Service Locator, where classes ask a central registry (the Service Locator) for their dependencies, rather than having them injected by an external Injector. There's a video about Service Locators on the channel too.

    • @rechnight
      @rechnight 2 месяца назад

      @@git-amend Thanks for the clarification! I thought of the Monobehaviours calling the Injector on themselves so that entities instantiated later on could also have the dependencies injected. How could this be solved with your Injector?

  • @HexGrimm
    @HexGrimm 8 месяцев назад

    You currently have only a partial implementation of Dependency Injection. When creation is delegated to a framework, it becomes the framework's responsibility to ensure that the entire graph is disposed of in the correct order and at the appropriate time. As it stands, this approach violates the RRR pattern.

    • @sisus_co
      @sisus_co 8 месяцев назад +3

      Components in Unity are already automatically released (destroyed) when their scene is unloaded. As such, it's not necessary for the DI framework to contain any custom code for figuring out when to release them.
      class Service : MonoBehaviour, IService, IDependencyProvider
      {
      [Provide] // Register
      IService IDependencyProvider.ProvideService() => this; // Resolve
      void OnDestroy() { ... } // Release
      }
      Unity is its own beast, with most of the object graph configuration usually taking place in edit mode, and being resolved by Unity automatically, so many traditional DI framework patterns don't necessarily transfer to Unity 1:1.

  • @nuin9937
    @nuin9937 8 месяцев назад

    Way too fast my brain is imploding

    • @git-amend
      @git-amend  8 месяцев назад +1

      You got this!

  • @-Engineering01-
    @-Engineering01- 2 месяца назад

    Too much overhead to make a DI framework even a little one. I'd prefer to buy that via asset store. Thanks 😊

    • @git-amend
      @git-amend  2 месяца назад +1

      If you are looking for a great DI tool that is easy to use from the store, I recommend this one. There is a free version as well.
      assetstore.unity.com/packages/tools/utilities/init-args-200530?aid=1101lw3sv

    • @-Engineering01-
      @-Engineering01- 2 месяца назад

      @@git-amend I bought it immediately thank you !