Skip to main content
  1. Quick Notes & Explanations/

7. What Are Zenject and VContainer Not?

·3 mins· loading · loading ·
Table of Contents

All of the systems mentioned above are frameworks. While I’ve provided examples specific to Unity, we could also include native C# frameworks like AutoFac, but these are systems adapted and optimized specifically for Unity.

No framework is written to add extra cost or difficulty to a project, but they can become outdated or fall behind modern systems if their developers stop supporting them.

What Are They Used For?

The purpose of these frameworks is actually completely independent of and unrelated to the application of SOLID principles.

To solve the multiple instance problem we encountered with Singletons, we could develop a custom plugin. Solving that problem in that specific scenario doesn’t mean we’ve entirely eliminated the issue. If we develop a comprehensive plugin that eliminates this fundamental problem with Singletons, it becomes a framework, and there’s no need to calculate a benefit/cost ratio.

Zenject and VContainer are frameworks that have anticipated and tested potential plugin development scenarios in situations like Scalable Multiple Instances, Interface Segregation, and Dependency Inversion, and have provided solutions in this context.

A Simple Example

  1. First, let’s create an interface to log our operations by applying the Interface Segregation principle.

    (Assume there are different types of Logger structures in the Editor and Build screens, and we use an interface for this purpose.)

    interface ILogger
    {
        void Log(string message);
    }
    
  2. Let’s create an EditorLogger using the ILogger interface and implement our method.

    public class EditorLogger : ILogger
    {
        public void Log(string message)
        {
            Debug.Log(message);
        }
    }
    
  3. Let’s inherit a class with an instance tied to the ILogger interface from the constructor of our Runner class and store and use it in a private variable.

    public class Runner
    {
        private ILogger _logger;
    
        public Runner(ILogger logger)
        {
            _logger = logger;
        }
    
        public void Run()
        {
            _logger.Log(Message to be logged);
        }
    }
    

    The code you see below is a Dependency Injection (yes, really):

    public class GameController
    {
        public GameController()
        {
            var logger = new EditorLogger();  // We created a “dependency”.
            var runner = new Runner(logger);  // We performed an “injection”.
            runner.Run();
        }
    }
    

    When we call our GameController class, we need to produce 2 dependent classes (dependencies).

    Now, imagine we are using this logic in a large project. We might need to pass these inheritances through constructors according to the dependencies between dozens of different classes. However, we can’t use principles like Singleton because ILogger is an interface and can have different types of instances.

    Here’s how we can solve our problem with VContainer:

  4. First, we define an address for all our instances and provide an entry point for our project. Here, GameController itself will be an entry point.

    public class GameLifetimeScope : LifetimeScope
    {
        protected override void Configure(IContainerBuilder builder)
        {
            builder.Register<ILogger>(Lifetime.Scope); // We registered to our interface.
            builder.Register<Runner>(Lifetime.Scope);
            builder.RegisterEntryPoint<GameController>();
        }
    }
    
  5. Our new GameController class will look like this:

    public class GameController
    {
        public GameController(Runner runner)
        {
            // VContainer handled all dependencies and injections.
            runner.Run();
        }
    }
    

    VContainer will create and set the ILogger instance required for the Runner class’s constructor. Inside the GameController, without using any new statements, we’ll receive the instances that VContainer created for us in our constructor.

Dependency Injection has solutions not just in this example but in multiple areas. I’ll try to touch on them as the need arises.

Reply by Email

Related

6. What is SOLID, and What is It Not?
·1 min· loading · loading
The following five principles, which we have previously explained, form our SOLID principles: Single Responsibility Principle Open/Closed Principle Liskov Substitution Principle Interface Segregation Principle Dependency Inversion Principle I won’t redefine these terms.
5. Choosing the Appropriate Architecture
·4 mins· loading · loading
After the reminders about optimization in the first three sections, we can bring together the principles from the fourth section to develop an architecture that can be applied to our project.
4. Design Pattern Examples
·10 mins· loading · loading
We can categorize Design Patterns under 3 main headings: Architectural Patterns Examples: MVC (Model-View-Controller), SOLID, MVVM… Design Patterns It is a specific Architectural Pattern, such as Singleton. Using it alone in a project is not sufficient, and optimization with several different patterns is necessary.
3. Why should we use architecture?
·3 mins· loading · loading
One of the fundamental advantages of working with principles and architectures in our projects is that it allows us to benefit from the advantages of libraries and plugins developed specifically for those principles.
2. GC Alloc ve GC Collect
·2 mins· loading · loading
In C# and some Object-Oriented Programming languages, there is the term Garbage Collector. However, in some mid-level programming languages, it is the programmer’s responsibility to remove objects that are no longer needed from memory.
1. Theory of Constraints & Games
·1 min· loading · loading
Theory of Constraints suggests that every production system has a single constraint that limits the producer from unlimited production, and the goal of the system is to continuously maximize the efficiency of that constraint.