Skip to main content

Implementation of Dependency Injection Pattern in C#

Dependency Injection (DI) is a software design pattern that allow us to develop loosely coupled code. DI is a great way to reduce tight coupling between software components. DI also enables us to better manage future changes and other complexity in our software. The purpose of DI is to make code maintainable.
The Dependency Injection pattern uses a builder object to initialize objects and provide the required dependencies to the object means it allows you to "inject" a dependency from outside the class.
For example, Suppose your Client class needs to use a Service class component, then the best you can do is to make your Client class aware of an IService interface rather than a Service class. In this way, you can change the implementation of the Service class at any time (and for how many times you want) without breaking the host code.
We can modify this code by the DI different ways. We have following different ways to implement DI :

Constructor Injection

  1. This is the most common DI.
  2. Dependency Injection is done by supplying the DEPENDENCY through the class’s constructor when instantiating that class.
  3. Injected component can be used anywhere within the class.
  4. Should be used when the injected dependency is required for the class to function.
  5. It addresses the most common scenario where a class requires one or more dependencies.
  1. public interface IService
  2. {
  3. void Serve();
  4. }
  5. public class Service : IService
  6. {
  7. public void Serve()
  8. {
  9. Console.WriteLine("Service Called");
  10. //To Do: Some Stuff
  11. }
  12. }
  13. public class Client
  14. {
  15. private IService _service;
  16. public Client(IService service)
  17. {
  18. this._service = service;
  19. }
  20. public void Start()
  21. {
  22. Console.WriteLine("Service Started");
  23. this._service.Serve();
  24. //To Do: Some Stuff
  25. }
  26. }
  27. class Program
  28. {
  29. static void Main(string[] args)
  30. {
  31. Client client = new Client(new Service());
  32. client.Start();
  33. Console.ReadKey();
  34. }
  35. }
The Injection happens in the constructor, by passing the Service that implements the IService-Interface. The dependencies are assembled by a "Builder" and Builder responsibilities are as follows:
  1. knowing the types of each IService
  2. according to the request, feed the abstract IService to the Client

Property injection

  1. Also called Setter injection.
  2. Used when a class has optional dependencies, or where the implementations may need to be swapped. Different logger implementations could be used this way.
  3. May require checking for a provided implementation throughout the class(need to check for null before using it).
  4. Does not require adding or modifying constructors.
  1. public interface IService
  2. {
  3. void Serve();
  4. }
  5.  
  6. public class Service : IService
  7. {
  8. public void Serve()
  9. {
  10. Console.WriteLine("Service Called");
  11. //To Do: Some Stuff
  12. }
  13. }
  14.  
  15. public class Client
  16. {
  17. private IService _service;
  18.  
  19. public IService Service
  20. {
  21. set
  22. {
  23. this._service = value;
  24. }
  25. }
  26.  
  27. public void Start()
  28. {
  29. Console.WriteLine("Service Started");
  30. this._service.Serve();
  31. //To Do: Some Stuff
  32. }
  33. }
  34. class Program
  35. {
  36. static void Main(string[] args)
  37. {
  38. Client client = new Client();
  39. client.Service = new Service();
  40. client.Start();
  41.  
  42. Console.ReadKey();
  43. }
  44. }

Method injection

  1. Inject the dependency into a single method, for use by that method.
  2. Could be useful where the whole class does not need the dependency, just the one method.
  3. Generally uncommon, usually used for edge cases.
  1. public interface IService
  2. {
  3. void Serve();
  4. }
  5.  
  6. public class Service : IService
  7. {
  8. public void Serve()
  9. {
  10. Console.WriteLine("Service Called");
  11. //To Do: Some Stuff
  12. }
  13. }
  14.  
  15. public class Client
  16. {
  17. private IService _service;
  18.  
  19. public void Start(IService service)
  20. {
  21. this._service = service;
  22. Console.WriteLine("Service Started");
  23. this._service.Serve();
  24. //To Do: Some Stuff
  25. }
  26. }
  27. class Program
  28. {
  29. static void Main(string[] args)
  30. {
  31. Client client = new Client();
  32. client.Start(new Service());
  33.  
  34. Console.ReadKey();
  35. }
  36. }

Key points about DI

  1. Reduces class coupling
  2. Increases code reusing
  3. Improves code maintainability
  4. Improves application testing

Comments

Popular posts from this blog

gcAllowVeryLargeObjects Element

There are numerous new features coming with .NET 4.5 and here, on this blog, you can find several posts about it. But the feature we are goint to talk about today is very exciting, because we were waiting for it more than 10 years. Since .NET 1.0 the memory limit of .NET object is 2GB. This means you cannot for example create array which contains elements with more than 2GB in total. If try to create such array, you will get the OutOfMemoryException. Let’s see an example how to produce OutOfMemoryException. Before that Open Visual Studio 2012, and create C# Console Application, like picture below. First lets create simple struct with two double members like example below: 1 2 3 4 5 6 7 8 9 10 11 12 public struct ComplexNumber {      public double Re;      public double Im;      public ComplexNumber( double re, double im)      {    ...

Support for debugging lambda expressions with Visual Studio 2015

Anyone who uses LINQ (or lambdas in general) and the debugger will quickly discover the dreaded message “Expression cannot contain lambda expressions”. Lack of lambda support has been a limitation of the Visual Studio Debugger ever since Lambdas were added to C# and Visual Basic.  With visual studio 2015 Microsoft has added support for debugging lambda expressions. Let’s first look at an example, and then I’ll walk you through current limitations. Example To try this yourself, create a new C# Console app with this code: using System.Diagnostics; using System.Linq; class Program { static void Main() { float[] values = Enumerable.Range(0, 100).Select(i => (float)i / 10).ToArray(); Debugger.Break(); } } Then compile, start debugging, and add “values.Where(v => (int)v == 3).ToArray()” in the Watch window. You’ll be happy to see the same as what the screenshot above shows you. I am using Visual Studio 2015 Preview and it has some limitati...

How to allow a very large object in .net application?

Since .NET 1.0 the memory limit of .NET object is 2GB. This means you cannot for example create array which contains elements with more than 2GB in total. If try to create such array, you will get the OutOfMemoryException. Let’s see an example how to produce OutOfMemoryException. Before that Open Visual Studio, and create C# Console Application. Lets create simple struct with two double members like example below: public struct ComplexNumber { public double Re; public double Im; public ComplexNumber(double re, double im) { Re = re; Im = im; } } As we know this structure consumes about 16 bytes of memory. So if we want to create array of this type which consume more than 2GB we need to create array at least with 134217728 instances. So this sample program below creates 130000000 (about 1,97 GB) of array. int maxCount = 130000000; ComplexNumber[] arr = null; try { arr = new ComplexNumber[maxCount]; } catch (Exception ex) { Console.WriteLine(ex.Message); } So if we run t...