DEV Community

Cover image for Dependency Inversion Principle (DIP) & Dependency Injection (DI) in C# (Easy Examples)
Abdullah Al Mamun Akand
Abdullah Al Mamun Akand

Posted on

2 2 2 2 2

Dependency Inversion Principle (DIP) & Dependency Injection (DI) in C# (Easy Examples)

🔹Understanding Dependency Inversion Principle


What is DIP?

DIP is a principle in SOLID design that says:

  • High-level code (business logic) should not depend on low-level code (implementation details).
  • Both should depend on an abstraction (interface or abstract class).

Why is DIP Important?

✅ Makes the code flexible – you can swap implementations easily.

Reduces dependencies – high-level modules don’t care about the details.

✅ Makes the code easier to test – we can use mock implementations.


🔹 Real-Life Example (Pizza Ordering System)

Imagine a restaurant with a Waiter and a Chef.

  • Bad Design (Without DIP):

    • The Waiter (business logic) goes to a specific chef (implementation) to make a pizza.
    • If the chef changes, the waiter also needs to change! ❌
  • Good Design (With DIP):

    • The Waiter doesn’t care who the chef is.
    • Instead, the Waiter follows an interface (IChef) to request the pizza.
    • Now, any chef (ItalianChef, RobotChef) can cook without changing the waiter! ✅

🔹 Without DIP (Bad Design - Tightly Coupled Code)

// Low-Level Module (Concrete Implementation)
public class ItalianChef
{
    public void MakePizza()
    {
        Console.WriteLine("Italian Chef is making a pizza!");
    }
}

// High-Level Module (Directly Dependent on Low-Level)
public class Waiter
{
    private ItalianChef _chef; // Direct dependency ❌

    public Waiter()
    {
        _chef = new ItalianChef(); // Hardcoded dependency ❌
    }

    public void TakeOrder()
    {
        _chef.MakePizza(); // Tightly coupled ❌
    }
}
Enter fullscreen mode Exit fullscreen mode

❌ Problems:

  • The Waiter is directly tied to ItalianChef.
  • If we want a RobotChef, we must change the Waiter class.
  • Hard to maintain, test, and extend.

🔹 With DIP (Good Design - Loosely Coupled Code)

Step 1: Create an Interface (Abstraction)

public interface IChef
{
    void MakePizza();
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Implement Different Chef Variants

public class ItalianChef : IChef
{
    public void MakePizza()
    {
        Console.WriteLine("Italian Chef is making a pizza!");
    }
}

public class RobotChef : IChef
{
    public void MakePizza()
    {
        Console.WriteLine("Robot Chef is making a pizza with automation!");
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Modify Waiter to Depend on an Interface

public class Waiter
{
    private IChef _chef; // Uses abstraction ✅

    public Waiter(IChef chef) // Inject dependency
    {
        _chef = chef;
    }

    public void TakeOrder()
    {
        _chef.MakePizza(); // Works with any chef ✅
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Use Dependency Injection

class Program
{
    static void Main()
    {
        IChef chef = new ItalianChef(); // Or new RobotChef();
        Waiter waiter = new Waiter(chef);
        waiter.TakeOrder(); // Output: Italian Chef is making a pizza!
    }
}
Enter fullscreen mode Exit fullscreen mode

✅ Now, the Waiter can work with ANY Chef (ItalianChef, RobotChef, etc.) without changing the Waiter class!


🔹 Understanding Dependency Injection (DI)

What is DI?

Dependency Injection is a technique where dependencies (like IChef) are provided from the outside instead of being created inside the class.

DI Techniques in C#

1️⃣ Constructor Injection (Best Practice)

   public class Waiter
   {
       private IChef _chef;

       public Waiter(IChef chef) // Injected via constructor
       {
           _chef = chef;
       }
   }
Enter fullscreen mode Exit fullscreen mode

2️⃣ Property Injection

   public class Waiter
   {
       public IChef Chef { get; set; } // Injected via property
   }
Enter fullscreen mode Exit fullscreen mode

3️⃣ Method Injection

   public class Waiter
   {
       public void TakeOrder(IChef chef) // Injected via method
       {
           chef.MakePizza();
       }
   }
Enter fullscreen mode Exit fullscreen mode

🔹 Combining DIP & DI for a Powerful System

1️⃣ DIP makes code loosely coupled

2️⃣ DI injects dependencies dynamically

3️⃣ Together, they make the code flexible & testable!

Example with a DI Container (ASP.NET Core)

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<IChef, ItalianChef>(); // Inject ItalianChef
builder.Services.AddScoped<Waiter>();

var app = builder.Build();
Enter fullscreen mode Exit fullscreen mode

Now, the framework automatically injects ItalianChef into Waiter!


Key Takeaways

Concept Explanation
DIP (Dependency Inversion Principle) High-level modules should not depend on low-level modules; both should depend on abstractions.
DI (Dependency Injection) A technique to provide dependencies from the outside instead of creating them inside the class.
Interface Role Interfaces act as the middle layer, allowing flexibility.
Best Practice Use DIP + DI together for loosely coupled, maintainable, and testable code.

Outcome

"DIP & DI = More Flexibility + Less Maintenance!"

If you follow these principles, your code will be scalable, reusable, and easy to modify!

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (2)

Collapse
 
chami profile image
Mohammed Chami

Dependency injection is the industry-standard way of implementing dependency inversion. Do not mix the two; one is a principle and the other refers to the implementation of this principle.
Thanks for sharing 🍀

Collapse
 
mamun_akand profile image
Abdullah Al Mamun Akand

Exactly, I tried to present the both in one place, as it all comes together here. That’s why DI was briefly explained as well. Thanks!

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay