Tuesday 29 May 2018

Dependency Injection in C#

Hi All,

I hope you are doing good.

This article demonstrates that what is "Dependency Injection" and how to use this to make the code loosely coupled.

Dependency Injection(DI)
Dependency Injection is the process of injecting (converting) coupled (dependent) objects into decoupled (Independent) object is called Dependency Injection(DI).

  • The dependency injection pattern one of the most popular design paradigms today.
  • It is process of removing dependency of object which creates the independent business objects (Loose coupling).
  • Loose coupling offers us greater reusability, maintainability and testability.
  • It is very useful for Test Driven Development(TDD).
  • DI also enables us to better manage future changes and other complexity in our software.

Scenario of Object Dependency:

    public class School
    {
        StaffTask objStaff = new StaffTask();
        StudentTask objStudent = new StudentTask();
    }

    class StaffTask
    {

    }

    class StudentTask
    {

    }
If you observe above classes, the School class dependent(coupled) on classes Staff and Student.
The tightly coupled objects all most impossible to reuse and implement unit tests because of the dependencies.

How to reduce dependency in above scenario?
Using the Dependency Injection, we can make above code loosely coupled (independent business objects).

There are four types of Dependency Injection(DI)
  1. Constructor Injection
  2. Setter Injection
  3. Interface-based Injection
  4. Service Locator Injection

Constructor Injection
  • This is most common DI.
  • Dependency Injection is done by supplying the Dependencies through the class constructor when instantiating class.
  • Injected class or component can be used anywhere within the class.

Following is the sample code base for how to understand constructor injection.

class Program
    {
        static void Main(string[] args)
        {
            // Consuming constructor injection
            School objSchool = new School(new StudentTask());
            Console.ReadLine();
        }
    }


    // Interface
    public interface ISchoolTasks
    {
        string TaskMethod();
    }

    // Implement interface
    public class StudentTask : ISchoolTasks
    {
        public string TaskMethod()
        {
            return "Student Task Method.";
        }
    }

    // Implement interface
    public class StaffTask : ISchoolTasks
    {
        public string TaskMethod()
        {
            return "Staff Task Method.";
        }
    }

    // Constructor Injection Implementation
    public class School
    {
        private ISchoolTasks client;

        // For below constructor we can pass wither "StudentTask" class object
        // or "StaffTask" classe object
        // from Main method
        public School(ISchoolTasks client)
        {
            this.client = client;
            Console.WriteLine("Constructor Injection Injection ==> Current Service: {0}", client.TaskMethod());
        }
    }

Getter and Setter Injection:
Getter and Setter Injection injects the dependency by using default public properties.

class Program
    {
        static void Main(string[] args)
        {
            // Consuming setter injection
            School objSchool = new School();
            objSchool.Client = new StudentTask();
            objSchool.TestSetterInj();
            Console.ReadLine();
        }
    }


    // Interface
    public interface ISchoolTasks
    {
        string TaskMethod();
    }

    // Implement interface
    public class StudentTask : ISchoolTasks
    {
        public string TaskMethod()
        {
            return "Student Task Method.";
        }
    }

    // Implement interface
    public class StaffTask : ISchoolTasks
    {
        public string TaskMethod()
        {
            return "Staff Task Method.";
        }
    }

    // Setter Injection Implementation
    public class School
    {
        private ISchoolTasks _client;

        public ISchoolTasks Client
        {
            get { return _client; }
            set { _client = value; }
        }

        public void TestSetterInj()
        {
            Console.WriteLine("Getter and Setter Injection ==> Current Service: {0}", Client.TaskMethod());
        }
    }

Interface-based Injection
We can pass object reference with the help of interface actions.

class Program
    {
        static void Main(string[] args)
        {
            // Consuming constructor injection
            School objSchool = new School();
            // StudentTask objStudent = new StudentTask();
            // OR
            StaffTask objStaff = new StaffTask();
            objSchool.setServiceRunService(objStaff);
            Console.ReadLine();
        }
    }


    // Interface
    public interface ISchoolTasks
    {
        string TaskMethod();
    }

    // Implement interface
    public class StudentTask : ISchoolTasks
    {
        public string TaskMethod()
        {
            return "Student Task Method.";
        }
    }

    // Implement interface
    public class StaffTask : ISchoolTasks
    {
        public string TaskMethod()
        {
            return "Staff Task Method.";
        }
    }

    //Support interface
    interface ISetService
    {
        void setServiceRunService(ISchoolTasks client);
    }

    //Implementing Interface Injection 
    public class School : ISetService
    {
        ISchoolTasks _client1;
        public void setServiceRunService(ISchoolTasks client)
        {
            _client1 = client;
            Console.WriteLine("Interface Injection ==> Current Service: {0}", _client1.TaskMethod());
        }
    }

Service Locator Injection:
  1. Service Locator Injection is also known as Dependency Absorption.
  2. It is used as a replacement for new operator.
  3. It hides the class dependency by invoking methods directly (without creating object).

The following code sample illustrates the concept, in the consumption setService method is invoked by class name School without creating object.

class Program
    {
        static void Main(string[] args)
        {
            // Consuming service locator injection
            School.setService(new StudentTask());
            // OR
            // School.setService(new StaffTask());
            ISchoolTasks client2 = School.getService();
            Console.WriteLine("Service Locator => Current Service : {0}", client2.TaskMethod());
            Console.ReadLine();
        }
    }


    // Interface
    public interface ISchoolTasks
    {
        string TaskMethod();
    }

    // Implement interface
    public class StudentTask : ISchoolTasks
    {
        public string TaskMethod()
        {
            return "Student Task Method.";
        }
    }

    // Implement interface
    public class StaffTask : ISchoolTasks
    {
        public string TaskMethod()
        {
            return "Staff Task Method.";
        }
    }

    //Business logic implementation for service locator injection
    public class School
    {
        private static ISchoolTasks _clientLocator;

        public static ISchoolTasks getService()
        {
            return _clientLocator;
        }

        public static void setService(ISchoolTasks clientSL)
        {
            _clientLocator = clientSL;
        }
    }

Advantages of Dependency Injection:

Following are the advantages of using Dependency Injection.
  • Reduces class coupling
  • Increases code reusability
  • Improves code maintainability
  • Improves application testing
  • Centralized configuration

I hope this will definitely useful for you while building the architectures of an applications.

Please raise your doubts in comments section will get back to you with answers.

Thanks all for reading this article!!

No comments:

Post a Comment

Intoduction to Flutter

Hi All, I hope every one is doing good In this article, we will know about the introduction of Flutter.