Click here to Skip to main content
15,867,969 members
Articles / Programming Languages / C#

Dependency Inversion Principle, IoC Container, and Dependency Injection: Part 1

Rate me:
Please Sign up or sign in to vote.
4.83/5 (72 votes)
28 Apr 2020CPOL4 min read 132.1K   207   29
Explanation about DIP and its need in the real time scenario
This is the first part of a series of articles on Dependency Injection. It will give you an idea about what is Dependency Inversion Principle. There are four other parts of the article which explain how to implement DIP.

Introduction

While working on a WPF application, I came across such kind of terms like Unity Container, IoC, Dependency Injection. At that time, I was confused, thinking of the need of all these. But later on, when I gradually knew about the benefits, I realized the actual need of it.

In this article, I will try to explain the need and usage of DI and IoC. Basically, this article is divided into five parts:

This part of the article is about Dependency Inversion Principle. Hope you will find this article easy to understand and implement.

Prerequisites

Better to have little knowledge on the following items:

  • Open/closed principle
  • Interface Segregation principle

Dependency Inversion Principle (DIP)

DIP is one of the SOLID principles, which was proposed by Sir Robert Martin C. in the year of 1992.

According to C. Robert Martin's Dependency Inversion Principle:

  1. High-level modules should not depend on low-level modules. Both should depend on abstractions.
  2. Abstractions should not depend upon details. Details should depend upon abstractions.

DIP refers to inverting the conventional dependency from high-level-module to low-level-module.

Example from Bob Martin Peper journal:

Image 1

In Figure 1.a copy program (high-level module) which reads from keyboard and writes to printer. Here the copy program depends on Read Keyboard and Write Printer and tightly coupled.

C#
public class Copy
{
    public void DoWork()
    {
        ReadKeyboard reader = new ReadKeyboard();
        WritePrinter writer = new WritePrinter();

        string data = reader.ReadFromKeyboard();
        writer.WriteToPrinter(data);
    }
}

This implementation seems perfectly fine until we have a requirement of adding more reader or writer to the program. In that case, we need to change the copy program to accommodate new readers and writers and need to write a conditional statement which will choose reader and writer based on the use, which violates Open/Close principle of object oriented design.

For example, we want to extend copy program (see figure 1.b) which also can read from scanner and write to flash disk. In such case, we need to modify our copy program:

C#
public class Copy
{
    public void DoWork()
    {
        string data;
        switch (readerType)
        {
            case  "keyboard":
                ReadKeyboard reader = new ReadKeyboard();
                data = reader.ReadFromKeyboard();
                break;
            case "scanner":
                ReadScanner reader2 = new ReadScanner();
                data = reader2.ReadFromScanner();
                break;
        }
        switch (writerType)
        {
            case "printer":
                WritePrinter writer = new WritePrinter();
                writer.WriteToPrinter(data);
                break;
            case "flashdisk":
                WriteFlashDisk writer2 = new WriteFlashDisk();
                writer2.WriteToFlashDisk(data);
                break;
        }
    }
}

Similarly, if you keep on adding more reader or writer, we need to change the implementation of copy program as copy program is depending on implementation of reader and writer.

To resolve this problem, we can modify our copy program to depend on abstractions rather depending on the implementation. The following figure explains about inverting the dependency.

Image 2

In the above figure, Copy program depends on two abstractions, IReader and IWriter to execute. As long as low level components confirm to the abstractions, copy program can read from those components.

Example, in the above figure, ReadKeyboard implements IReader interface and WritePrinter implements IWriter, hence using IReader and IWriter interface copy program can perform copy operation. So if we need to add more low level components such as scanner and flash disk, we can do so by implementing from scanner and flash disk. The following code illustrates the scenario:

C#
public interface IReader
{
    string Read();
}

public interface IWriter
{
    void Write(string data);
}

public class ReadKeyboard : IReader
{
    public string Read()
    {
        // code to read from keyboard and return as string
    }
}

public class ReadScanner : IReader
{
    public string Read()
    {
        // code to read from scanner and return as string
    }
}

public class WritePrinter : IWriter
{
    public void Write(string data)
    {
        // code to write to the printer
    }
}

public class WriteFlashDisk : IWriter
{
    public void Write(string data)
    {
        // code to write to the flash disk
    }
}

public class Copy
{
    private string _readerType;
    private string _writerType;

    public Copy(string readerType, string writerType)
    {
        _readerType = readerType;
        _writerType = writerType;
    }

    public void DoWork()
    {
        IReader reader;
        IWriter writer;
        string data;
        switch (readerType)
        {
            case  "keyboard":
                reader = new ReadKeyboard();
                break;
            case "scanner":
                reader = new ReadScanner();
                break;
        }

        switch (writerType)
        {
            case "printer":
                writer = new WritePrinter();
                break;
            case "flashdisk":
                writer = new WriteFlashDisk();
                break;
        }

        data = reader.Read();
        writer.Write(data);
    }
}

In this case, details depend on abstractions but still high-level class depends on low-level modules. As we are instantiating low-level module object in the scope of high-level module, high-level module still needs modification on addition of new low-level components, which doesn't fully satisfy DIP.

In order to remove the dependency, we need to create the dependency object (low-level component) outside of high-level module, and there should be some mechanism to pass that dependency object to depending module.

Now a new question arises, how can we implement Dependency Inversion.

One of the answers to the above question can be Inversion of Control (IoC). Consider the following code segment:

C#
public class Copy
{
    public void DoWork()
    {
        IReader reader = serviceLocator.GetReader();
        IWriter writer = serviceLocator.GetWriter();
        string data = reader.Read();
        writer.Write(data);
    }
}

The highlighted code replaces the logic to instantiate reader and writer object. Here, we are inverting the control creation from Copy program (high-level module) to service locator. Hence the copy program need not be changed with any addition/removal of low-level module.

Dependency Injection is one of the mechanisms to implement IoC. In the next parts of this article, I will be covering what is an Inversion of Control (IoC), and the way to implement the Dependency Inversion Principle using different mechanism (Dependency Injection (DI) is one of the implementations).

Summary

In this part of the article, I have explained Dependency Inversion Principle (DIP), and its need in the real time scenario.

In later part of the article, I will explain Inversion of Control (IoC) and Dependency Injection (DI).

History

  • 29th April, 2020, Fixed typos
  • 12th March, 2013: First revision

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
PAREXEL International
India India
Life is short. So enjoy each and every moment of life.
And necessarily keep smiling. Smile | :)

Comments and Discussions

 
QuestionIWriter interface typo Pin
brewmanz24-Apr-20 12:21
brewmanz24-Apr-20 12:21 
AnswerRe: IWriter interface typo Pin
Chinmaya C28-Apr-20 15:59
Chinmaya C28-Apr-20 15:59 
Generalgreat article Pin
Member 1399748325-Sep-18 10:40
Member 1399748325-Sep-18 10:40 
GeneralMy vote of 5 Pin
Member 1221544917-Dec-15 22:31
Member 1221544917-Dec-15 22:31 
GeneralMy vote of 4 Pin
ccamatthews2-Sep-14 4:20
ccamatthews2-Sep-14 4:20 
Nice synthesis of concepts in the whole series
GeneralRe: My vote of 4 Pin
Chinmaya C10-Sep-14 6:07
Chinmaya C10-Sep-14 6:07 
QuestionCorrect function implementation? Pin
Rudolf Grauberger1-May-14 2:35
Rudolf Grauberger1-May-14 2:35 
AnswerRe: Correct function implementation? Pin
Chinmaya C6-Jun-14 4:47
Chinmaya C6-Jun-14 4:47 
QuestionIoC - real or imagined? Pin
rrotstein11-Feb-14 9:11
rrotstein11-Feb-14 9:11 
AnswerRe: IoC - real or imagined? Pin
Chinmaya C11-Feb-14 17:15
Chinmaya C11-Feb-14 17:15 
GeneralMy vote of 5 Pin
AmitGajjar16-May-13 6:37
professionalAmitGajjar16-May-13 6:37 
GeneralRe: My vote of 5 Pin
Chinmaya C16-May-13 8:03
Chinmaya C16-May-13 8:03 
GeneralExcellent presentation - couple small typos Pin
tiredoldcoder24-Apr-13 22:49
tiredoldcoder24-Apr-13 22:49 
GeneralRe: Excellent presentation - couple small typos Pin
Chinmaya C24-Apr-13 23:31
Chinmaya C24-Apr-13 23:31 
GeneralMy vote of 5 Pin
Member 865734524-Apr-13 5:39
Member 865734524-Apr-13 5:39 
GeneralRe: My vote of 5 Pin
Chinmaya C24-Apr-13 6:41
Chinmaya C24-Apr-13 6:41 
GeneralMy vote of 5 Pin
Patrick Skelton22-Apr-13 22:25
Patrick Skelton22-Apr-13 22:25 
GeneralRe: My vote of 5 Pin
Chinmaya C22-Apr-13 22:42
Chinmaya C22-Apr-13 22:42 
GeneralMy vote of 5 Pin
mariuszkiler21-Apr-13 7:50
mariuszkiler21-Apr-13 7:50 
GeneralRe: My vote of 5 Pin
Chinmaya C22-Apr-13 22:42
Chinmaya C22-Apr-13 22:42 
GeneralMy vote of 5 Pin
GregoryW16-Apr-13 1:54
GregoryW16-Apr-13 1:54 
GeneralRe: My vote of 5 Pin
Chinmaya C16-Apr-13 5:15
Chinmaya C16-Apr-13 5:15 
GeneralMy vote of 5 Pin
Gajendra Medatia5-Apr-13 0:12
Gajendra Medatia5-Apr-13 0:12 
GeneralRe: My vote of 5 Pin
Chinmaya C5-Apr-13 0:28
Chinmaya C5-Apr-13 0:28 
GeneralMy vote of 4 Pin
SRIRAM 24-Apr-13 20:59
SRIRAM 24-Apr-13 20:59 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.