Inversion of Control in C#
In this article, I am going to discuss the Inversion of Control in C#. Please read our previous article, where we discussed the Abstract Factory Design Pattern in C# with examples. As a developer, you may be familiar with the terms IoC (Inversion of Control), DIP (Dependency Inversion Principle), DI (Dependency Injection) Design pattern, and IoC containers. But are you confident what each term means with some real-time examples? If you are not confident about each of these terms then you are in the right place. Here we will discuss each of these terms. As part of this article, we are going to discuss the following pointers.
- Difference between Design Principle and Design Pattern
- Inversion of Control (IoC)
- Understanding the Dependency Inversion Principle.
- Understanding the Dependency Injection Design Pattern
- IoC Container
Difference between Design Principle and Design Pattern
In the programming world, both design principles and design patterns are not the same. Let’s discuss the differences between them.
The Design principles are provided with some high-level guidelines or you can say mechanism to make the software designs more understandable, flexible as well as maintainable. They (i.e. Design Principles) do not provide any implementation and also they are not bound to any programming languages. So, you can use design principles irrespective of the programming languages.
E.g. SOLID (SRP, OCP, LSP, ISP, DIP) Design Principles.
For example, the Single Responsibility Principle (SRP) states that a class should have only one reason to change. This is the high-level statement which we need to keep in mind while designing the classes for our application. The SRP does not provide any specific implementation steps but it’s up to us how we implement the Single Responsibility Principle in our application.
The Design patterns are reusable solutions to the problems that we encounter in our day to day programming. They are basically used to solve the problems of object generation and integration. For example, if you want to create a class that can have only one instance for the entire application then you can use Singleton design pattern which ensures that a class has only one instance for the entire application and provides a global point of access to it.
There are so many design patterns that are tested by others and safe to follow. For example. Gang of Four patterns: Abstract Factory, Factory, Singleton, etc.
Once you understand the difference between Design Patterns and Design Principles, let’s understand the terms IoC (Inversion of Control), DIP (Dependency Inversion Principle), DI (Dependency Injection) Design pattern, and IoC containers.
The following diagram gives you a clear idea of whether they are principles or patterns or frameworks.
As principles, they only provide some high-level guidelines or mechanisms to develop software application but they do not provide any specific implementation details. Dependency Injection is a design pattern whereas IoC container is a framework.
Let’s have a look at each term before going into details.
Inversion of Control (IoC):
The main objective of Inversion of control (IoC) is to remove dependencies between the objects of an application which makes the application more decoupled and maintainable.
IoC design principle suggests the inversion of various types of controls in object-oriented design to achieve loose coupling between the application classes. Here, the control means any extra responsibilities a class has other than its main or fundamental responsibility. For example, control over the flow of an application, control over the dependent object creation, etc.
Let’s say you have a “repository” class, and that the repository class is responsible for giving data to you from a data source.
The repository class could establish a connection to the data source by itself without anyone else’s input. But, consider the situation, what if it is allowed you to pass the connection details about the data source through the repository class constructor?
By allowing the caller to provide the connection details through a class constructor, we have actually decoupled the data source connection dependency from the repository class, allowing any data source to work with the repository, not the one which the repository specifies.
Here, we have inverted the control by handing the responsibility of creating the connection details about the data source from the repository class to the caller class.
Martin Fowler recommends using the term “Dependency Injection” to describe this type of Inversion of Control since Inversion of Control is a principle, it can be utilized more comprehensively than simply injecting dependencies in a constructor method.
I will discuss IoC in detail in the next article.
Understanding the Dependency Inversion Principle:
Dependency Inversion Principle also helps us to achieve loose coupling between the classes. It is highly recommended to use both DIP and IoC together in order to achieve loose coupling between the classes.
The DIP (DIP) states that high-level modules/classes should not depend upon low-level modules/classes. Both should depend upon abstractions. Secondly, abstractions should not depend upon details. Details should depend upon abstractions.
We need to keep the High-level module and Low-level module as loosely coupled as possible.
When a class knows about the design and implementation of another class, it raises the risk that if we do any changes to one class will break the other class. So we must keep these high-level and low-level modules/classes loosely coupled as much as possible. To do that, we need to make both of them dependent on abstractions instead of knowing each other.
DIP principle is invented by Robert Martin (a.k.a. Uncle Bob). He is a founder of SOLID principles. We will discuss DIP in detail in our upcoming articles.
Understanding the Dependency Injection Design Pattern:
The Dependency Injection (DI) design pattern is a software design pattern that allows us to develop loosely coupled code by inverting the creation of dependent objects.
Dependency Injection is a great way to reduce the tight coupling between software components. DI also enables us to better manage future changes and other complexity in our software.
The IoC Container is a great framework to create dependencies and inject them automatically whenever required throughout the application so that we as a software programmer don’t have to put additional time and effort into it. It automatically creates the necessary objects based on the request and also automatically injects them whenever required. DI Container helps us to manage dependencies within the application in a straightforward and simple way.
There are different IoC Containers available for .NET such as Unity, Ninject, StructureMap, Autofac, etc. I will discuss more regarding the IoC Container chapter in our upcoming articles.
We can’t accomplish loosely coupled classes by just utilizing IoC. Along with IoC we additionally need to utilize DIP, DI and IoC containers to achieve loosely coupled.
The following diagram illustrates how we are going to achieve loosely coupled design step by step in the next few upcoming articles.
In the next article, I am going to discuss the Inversion of Control using Factory Pattern in C# with examples. Here, in this article, I try to explain the Inversion of Control in C#. I hope this article will help you with your needs. I would like to have your feedback. Please post your feedback, question, or comments about this article.