This slide explains the usage of dependency injection in order to write more precise code.
More Details: https://www.loginworks.com/technical-blogs/implement-dependency-injection-c/
2. PROBLEM SCENARIO
Objects can be loosely or tightly coupled. Tightly coupled objects have dependencies on
concrete objects due to which they have lower reusability, maintainability, and testability.
Tightly coupled object provide lesser dynamicity due to which user need to change the
implementation of class and it’s member functions. We can achieve this via Dependency
Injection.
3. WHAT DEPENDENCY INJECTION DO?
Irrelevant dependencies increase code complexity which results in increased loading and
execution time of application. Dependency Injection (DI) is a solution design which
provides development of the loosely coupled code. ‘Loose Coupling‘ means the object will
only have those dependencies which are required to do their work. Loosely coupled code
increases the modularity of application which offers us greater reusability, maintainability,
and testability.
Note: For more details on loosely coupled coding guidelines, please follow Dependency
Inversion Principle.
4. TYPES OF DEPENDENCY INJECTION
In general, there are three types of DI,
1. Constructor Injection
2. Property or Setter Injection
3. Method Injection
5. CONSTRUCTION INJECTION
It uses parameters to inject dependencies. The object has no defaults or single
constructor due to which specified values are required at the time of creation to instantiate
the object. This is the most common type of DI. We can use injected component anywhere
in the class. It makes a strong dependency contract.
In this type, we can make dependency immutable in order to prevent it from circular
dependency. For entire dependency graph, it requires up-front wiring which needs a
public constructor in the class to pass dependency as a parameter.
6. CONSTRUCTION INJECTION EXAMPLE
Consider a scenario, where a student took admission in school and school provides bag,
dress, books etc to that student. Here, the student does not like to receive goodies from
different counters. What the student would like, that he/she should receive all the goodies
from a single counter in one go.
Create a console application of any name and create two classes. See below image.
7.
8. In above image, SchoolBag and SchoolDress are the basic ‘Service classes’ having Bag
and Dress methods respectively.
In the image below, Student class is ‘Client class’ using the service (i.e. SchoolBag ) and
assigning that bag to ‘John’ in the main program.
9.
10. The Student constructor is assigning a new instance of SchoolBag class. And the Assign
method is acting like a Service_Start() method. It is receiving the studentName from the
main program and passing it to Bag method of SchoolBag class.
OUTPUT
The output of above implementation will be,
11. Above implementation has one issue i.e. we only managed to assign SchoolBag to the
Student. SchoolDress is still left or what if we want to provide some other things to the
student. Since the object of SchoolBag is created inside the Student class’s constructor,
we have to modify the implementation of Student class for SchoolDress and the for some
other thing, which is not a proper implementation. This is a type of concrete dependency.
To avoid this, we can use interfaces to provide a level of indirection. See the below
implementation.
12. IMPLEMENTING INTERFACE
Create a service interface.
interface IThings
{
void Assign(string studentName);
}
and now remove the previous implementation of the service classes (i.e. SchoolBag and
SchoolDress ) and implement the above service interface in the service classes. Like this,
13. After this, we need to alter our client class. We need to “inject” a parameter of service
interface type (i.e. IThings ) in the constructor of Student class.
14.
15. In above image, we have injected a new object into the client class. And we can use this
object anywhere in the client class. Below is the respective output.
16. SETTER or PROPERTY INJECTION
In this, we don’t require to change the constructor. We pass dependencies through the
exposed public properties. In this, we can create costly resources or services as late as
possible and only when required. It is difficult to identify which dependencies are required
and it is beneficial to perform null checks in setter properties. For entire dependency
graph, it does not require up-front wiring.
In addition to our previous code, the implementation we did for Student constructor has
now been transferred to the setter of SetStudent property. And the new object which was
previously passed as a parameter in the constructor of Student class, has now been
assigned to the SetStudent property in the main program. The output will be same as it
was for constructor injection. See the following image.
17.
18. METHOD INJECTION
In this, the dependency is been injected within a single method to be used by that method
only. It is useful in case when only one method needs dependency, not the whole class.
In addition to our previous code, the implementation we did for setter property has now
been transferred to the Assign method and the dependency has been injected as a
parameter from main program. The output will be same as it was for property injection.
See the following image.
19.
20. BENEFITS OF USING DEPENDENCY INJECTION
With DI, you can inject extra code between the conditions. To illustration, you can utilize
the Constructor Injection to give an instance its conditions. In the event that you have a
class with ten functions that have no dependencies. Then, you have to include one or
more than one function with a dependency. You can change the constructor to utilize
Constructor Injection.
Then again, you can basically include another constructor that takes the dependency as a
parameter. However, in the event that there is a dependency which is costly to make, you
can utilize the Setter Injection. It gives you a chance to make the expensive resources
only when required. As should be obvious, DI makes code testable, viable, reusable and
coherent.