- C# - Home
- C# - Overview
- C# - Environment
- C# - Program Structure
- C# - Basic Syntax
- C# - Data Types
- C# - Type Conversion
- C# - Variables
- C# - Constants
- C# - Operators
- C# - Arithmetic Operators
- C# - Assignment Operators
- C# - Relational Operators
- C# - Logical Operators
- C# - Bitwise Operators
- C# - Miscellaneous Operators
- C# - Operators Precedence
- C# Conditional Statements
- C# - Decision Making
- C# - If
- C# - If Else
- C# - Nested If
- C# - Switch
- C# - Nested Switch
- C# - Switch Expressions
- C# Control Statements
- C# - Loops
- C# - For Loop
- C# - While Loop
- C# - Do While Loop
- C# - Nested Loops
- C# - Break
- C# - Continue
- C# - Foreach Loop
- C# - Goto Statement
- C# OOP & Data Handling
- C# - Encapsulation
- C# - Methods
- C# - Nullables
- C# - Arrays
- C# - Strings
- C# - Structure
- C# - Enums
- C# - Classes
- C# - Inheritance
- C# - Polymorphism
- C# - Operator Overloading
- C# - Interfaces
- C# - Namespaces
- C# - Preprocessor Directives
- C# - Regular Expressions
- C# - Custom Exceptions
- C# - Exception Handling
- C# - File I/O
- C# Advanced Tutorial
- C# - Attributes
- C# - Reflection
- C# - Properties
- C# - Indexers
- C# - Delegates
- C# - Events
- C# - Collections
- C# - Generics
- C# - LINQ
- C# - IEnumerable vs IEnumerator
- C# - Anonymous Methods
- C# - Unsafe Codes
- C# - Tasks and Parallel Programming
- C# - Multithreading
- C# - Extension Methods
- C# - Lambda Expressions
- C# - Async and Await
- C# Modern Features
- C# - Tuples
- C# - Records
- C# - Pattern Matching Enhancements
- C# - Top-level Statements
- C# - Nullable Reference Types
- C# - What's New in C# 11 / 12 / 13
- C# - Global Usings
- C# - File-Scoped Namespaces
- C# Practical & Advanced Usage
- C# - JSON & XML Handling
- C# - Data Serialization & Deserialization
- C# - REST API Calls with Httpclient
- C# - Dependency Injection
- C# - Unit Testing with NUnit, xUnit & MSTest
- C# - Package Management with NuGet
Dependency Injection in C#
Dependency Injection (DI) is one of the most important concepts in modern C# (.Net) development, especially for writing clean, testable, and maintainable code. DI is a design pattern that helps you to create loosely coupled, flexible and testable applications.
What is Dependency Injection?
In C# .Net, they have good support for DI, which stands for Dependency Injection. It is a technique for achieving inversion of control (IoC) between classes and their dependencies. DI in .NET is a built-in part of the framework, along with configuration logging and the design pattern.
In Inversion of Control (IoC), the control of object creation and dependency management is taken away from the class itself and given to an external source (like a framework or container).
A dependency is an object that another object depends on.
Let's understand with the following example. Suppose we have a class called "College" that manages technical events. Inside the College class, we create an object of another class called "TechEvents".
Example 1: Without Inversion of Control
// Example 1: Without Inversion of Control
// Tightly Coupled Classes
using System;
public class TechEvents {
public void OrganizeEvent() {
Console.WriteLine("Organizing Tech Event...");
}
}
public class College {
private TechEvents _techEvent;
public College() {
// College is responsible for creating TechEvents
_techEvent = new TechEvents();
}
public void StartEvent() {
_techEvent.OrganizeEvent();
}
}
public class Program {
public static void Main() {
College college = new College();
college.StartEvent();
}
}
Following is the output
Organizing Tech Event...
Explanation
- Here, "College' and "TechEvents" are tightly coupled, one cannot exist without the other.
- If the TechEvents class changes, we must also modify and recompile the College class.
- College is directly controlling how TechEvents objects are created.
- If we want to organize a different event like FootballEvent or PartyEvent, we'll have to change the College class.
Example 2: With Inversion of Control
// Example 2: With Inversion of Control
// Loosely Coupled Using Interface and Injection
using System;
public interface IEvent {
void OrganizeEvent();
}
public class TechEvents : IEvent {
public void OrganizeEvent() {
Console.WriteLine("Organizing Tech Event...");
}
}
public class FootballEvent : IEvent {
public void OrganizeEvent() {
Console.WriteLine("Organizing Football Event...");
}
}
public class College {
private readonly IEvent _eventService;
// Constructor Injection â dependency provided from outside
public College(IEvent eventService) {
_eventService = eventService;
}
public void StartEvent() {
_eventService.OrganizeEvent();
}
}
public class Program {
public static void Main() {
// You can easily switch between events without modifying College
IEvent techEvent = new TechEvents();
College college1 = new College(techEvent);
college1.StartEvent();
IEvent footballEvent = new FootballEvent();
College college2 = new College(footballEvent);
college2.StartEvent();
}
}
Following is the output
Organizing Tech Event... Organizing Football Event...
Explanation
- Here, "College" doesn't create or control TechEvents.
- We can inject any event type, FootballEvent, PartyEvent, or TechEvents without changing the College code.
- The control of object creation has been inverted (shifted to the caller or framework).
Type of Dependency Injection
There are mainly three type of Dependency Injection in C#
- Constructor Injection
- Property or Setter Injection
- Method Injection
1. Constructor Injection
In C#, Constructor Injection is the most common and suggested form of dependency injection. In this type, the dependency is provided through a class constructor. When the object is created, its required dependencies are passed as parameters to the constructor.
Example
In the following example, we demonstrate how the Constructor Injection (CI) will work.
using System;
public interface IMessageService {
void SendMessage(string message);
}
public class EmailService : IMessageService {
public void SendMessage(string message) {
Console.WriteLine("Email sent: " + message);
}
}
public class Notification {
private readonly IMessageService _messageService;
// Dependency is injected through the constructor
public Notification(IMessageService messageService) {
_messageService = messageService;
}
public void Notify(string message) {
_messageService.SendMessage(message);
}
}
class Program {
static void Main() {
IMessageService emailService = new EmailService();
Notification notification = new Notification(emailService);
notification.Notify("Hello from Constructor Injection");
}
}
Following is the output −
Email sent: Hello from Constructor Injection
Advantages:Constructor injection ensures dependencies are always provided at object creation, allowing immutability and clear contracts.
2. Property (Setter) Injection
In C#, Property Injection, dependencies are assigned to public properties after the object is created. This allows flexibility if dependencies need to be changed later, but it also means the class may exist in an incomplete state until properties are set.
Example
In the following example, we demonstrate how the Property Injection (PI) will work.
using System;
public interface IMessageService {
void SendMessage(string message);
}
public class EmailService : IMessageService {
public void SendMessage(string message) {
Console.WriteLine("Email sent: " + message);
}
}
public class Notification {
public IMessageService MessageService { get; set; }
public void Notify(string message) {
MessageService.SendMessage(message);
}
}
class Program {
static void Main() {
Notification notification = new Notification();
// Inject via property
notification.MessageService = new EmailService();
notification.Notify("Hello from Property Injection");
}
}
Following is the output −
Email sent: Hello from Property Injection
Advantages − Property Injection provides flexibility to change dependencies dynamically.
Disadvantages − The class might not function properly if the property isn't initialized.
3. Method Injection
In C#, Method Injection, dependencies are passed directly to the method that needs them. It is useful when only specific methods require certain dependencies instead of the entire class.
Example
In the following example, we demonstrate how the Method Injection (MI) will work.
using System;
public interface IMessageService {
void SendMessage(string message);
}
public class EmailService : IMessageService {
public void SendMessage(string message) {
Console.WriteLine("Email sent: " + message);
}
}
public class Notification {
public void Notify(IMessageService messageService, string message) {
messageService.SendMessage(message);
}
}
class Program {
static void Main() {
IMessageService emailService = new EmailService();
Notification notification = new Notification();
notification.Notify(emailService, "Hello from Method Injection");
}
}
Following is the output −
Email sent: Hello from Method Injection
Advantages − Method Injection provides detailed control and is perfect when dependency is only required for one method.
Disadvantages − Can lead to repetitive code if the same dependency is required in multiple methods.
Advantages of Dependency Injection
Following is the advantage of using the DI −
- It promotes loose coupling
- It improve code maintainability
- It optimize the testability using mock objects
- It maximizes productivity and minimizes rework
Conclusion
Dependency injection simplifies class interaction by removing tight coupling between them. It enables you to create applications that are clean, modular, and easy to test. By using .NET's built-in DI, you can effectively handle dependencies and also make your application more flexible and manageable.