In a recent blog post, we talked about how C# and .NET are the next big thing. If you’re planning to code in C#, dependency injection is just one of many things you should know. Read on for a primer on dependency injection in C# so you can use it to your advantage in your next project.
If you take a closer look at Dependency Injection (DI), it is a software design pattern which enables the development of loosely coupled code. Through DI, you can decrease tight coupling between software components. It is also known as Inversion-of-Control, which makes unit testing convenient.
It is critical to take a step back to the basics of designing an object-oriented application where a major facet of design is “loose coupling.” This means that objects only have as many dependencies as needed to do their jobs–and, the number of dependencies should be limited.
In addition, an object’s dependencies should be on interfaces as opposed to “concrete” objects. What is a concrete object? This is any object created with the keyword “new.” Through loose coupling, you enable easier maintainability and greater reusability. Moreover, you can feature “mock” objects designed to take the place of costly services such as a socket-communicator. There are three types of DIs:
Since DI is utilized to make code maintainable, it uses a pattern with a builder object to initialize objects and give the required dependencies to the object. As you can see, you can now “inject” a dependency from outside the class.
To illustrate, if your Client class needs to use a Service class component, the most you can do is make your Client aware of an IService interface instead of a Service class. Through this execution, you get to change the implementation of the Service class as many times as you like without breaking the host code.
It is helpful to understand the Dependency Inversion Principle, which gives us the guidelines for writing loosely-coupled classes. Here is the definition:
How do you get two modules to depend on each other? Through Inversion of control. This is the actual mechanism you can use to make higher-level modules that depend on abstractions. You must invert the control to follow the dependency inversion principle. As a result, your high-level modules are no longer dependent on the lower-level concrete implementations.
Let’s dive a bit deeper into the three types of Dependency Injections:
The basic premise here is that the object has no defaults or a single constructor. What is required are specified values at the time of creation to instantiate the object. In a nutshell, Constructor Injection uses parameters to inject dependencies. This is the most common DI, which is executed by supplying the dependency through the class’s constructor when instantiating that class.
In addition, an injected component can be used anywhere within the class. Although, it should be used when the injected dependency is required for the class to function. Furthermore, the Constructor Injection is used within the most common scenario when a class requires one or more dependencies. Here are a few advantages of the Constructor Injection:
This is also called the Property Injection. The Setter Injection lets us create costly resources and services only as required and as late as possible. Plus, it does not require up-front wiring of the entire dependency graph. The only issue is it can be difficult to identify which dependencies are required. Although, it does not require adding or modifying constructors. Furthermore, you will need to check for null before using it.
This is the least common and only used for edge cases. As the name states, Method Injection injects the dependency into a single method to be utilized by that method. As a result, it is useful when the whole class only needs the one method and not the dependency.
With DI, you can inject additional code between the dependencies. To illustrate, you can use the Constructor Injection to give an object its dependencies. If you have a class with 10 methods that have no dependencies, but you want to add a new method with a dependency–you can change the constructor to use Constructor Injection.
On the other hand, you can simply add a new constructor that takes the dependency. Yet, if a dependency is expensive to create, you can use the Setter Injection since it lets you create the costly resources only when needed. As you can see, DI makes code testable, maintainable, reusable and readable.