35 Dependency Injection Interview Questions & Answers
Dependency Injection interviews are less about syntax and more about reasoning — why it exists, what it actually buys you over just constructing dependencies directly, and where it can be misused. This covers all 35 questions, organized by topic, with code, a diagram, and a mock test at the end.
DI Fundamentals
Q1. What is Dependency Injection and why is it used in modern software development?
// Without DI — the class builds its own dependency
public class OrderService
{
private readonly EmailSender _email = new EmailSender();
}
// With DI — the dependency is supplied from outside
public class OrderService
{
private readonly IEmailSender _email;
public OrderService(IEmailSender email) => _email = email;
}Dependency Injection means a class declares what it needs (usually via its constructor) instead of constructing those dependencies itself — something external (a DI container, or just calling code) supplies them. It's used because it decouples a class from the concrete implementations it depends on, which is exactly what makes swapping implementations, mocking dependencies in tests, and changing behavior through configuration all possible without touching the class's own code.
Q2. Explain the concept of Inversion of Control (IoC) and how it relates to Dependency Injection.
Inversion of Control is the broader principle: instead of your code controlling the flow and creating what it needs, control is handed to a framework/container that calls into your code and supplies what it needs. Dependency Injection is the specific, most common technique for achieving IoC for object dependencies — IoC is the principle, DI is one implementation of it (alongside others like the Service Locator pattern or event-driven callback registration).
Q3. What are the main advantages of using Dependency Injection in a software project?
- Testability — swap a real dependency for a mock/fake without changing the class under test
- Loose coupling — a class depends on an interface/abstraction, not a concrete implementation
- Flexibility — swap implementations (a different payment gateway, a different logger) via configuration, not code changes
- Centralized lifetime/configuration management through the container instead of scattered manual construction
Q4. Describe the impact of Dependency Injection on the maintainability of code.
Because classes depend on abstractions rather than concrete types, changing or replacing an implementation touches the registration/composition point, not every class that uses it — a change that would otherwise ripple through many constructors instead becomes a one-line change in the DI configuration. The trade-off is a layer of indirection: tracing "what actually implements this interface" requires checking the container's registration, not just reading the class.
Q5. Can you explain the Dependency Inversion Principle and how it differs from Dependency Injection?
| Dependency Inversion Principle (the 'D' in SOLID) | Dependency Injection | |
|---|---|---|
| What it is | A design principle: depend on abstractions, not concretions | A technique: supply dependencies from outside instead of constructing them internally |
| Scope | How you should structure relationships between modules | How you actually wire up and provide those dependencies at runtime |
They're related but distinct: you can follow the Dependency Inversion Principle (code against IEmailSender, not SmtpEmailSender) without using DI at all (just new SmtpEmailSender() somewhere), and conversely DI is most valuable specifically when combined with DIP — injecting a concrete class instead of an interface still works mechanically, but loses most of DI's actual benefit.
Types of Dependency Injection
Q6. Compare and contrast constructor injection versus setter injection.
| Constructor injection | Setter (property) injection | |
|---|---|---|
| When supplied | At construction time — required upfront | After construction — can be set later, or left unset |
| Immutability | Supports readonly fields — dependency can never change after construction | Dependency is mutable, can be reassigned |
| Enforces required dependencies? | Yes — can't construct the object without them | No — the object can exist in a half-configured state |
| Preferred for | Required dependencies (the common default) | Optional dependencies, or frameworks that require a parameterless constructor |
// Constructor injection — required, immutable
public class OrderService
{
private readonly IEmailSender _email;
public OrderService(IEmailSender email) => _email = email;
}
// Setter injection — optional, can change later
public class OrderService
{
public ILogger Logger { get; set; } // fine if null — just means "don't log"
}Q7. When would you use method injection instead of constructor injection?
public void ProcessOrder(Order order, ICurrencyConverter converter)
{
var total = converter.Convert(order.Total, "USD");
// converter is only needed for this one call, not for the object's whole lifetime
}Method injection supplies a dependency as a parameter to one specific method rather than the whole object — appropriate when a dependency is only relevant to that one operation, not something the class needs for its entire lifetime, so it doesn't belong in the constructor at all.
Q8. Can mixing different types of injection in the same class lead to issues? If so, what kind?
It can make a class's actual requirements unclear — some dependencies enforced by the constructor, others optionally set via properties that might silently remain null, and a reader has to check every injection point to know what's actually required to use the class safely. Most teams pick one primary style (constructor injection for required dependencies) and use others sparingly and consistently, rather than mixing freely per class.
Q9. Is there a preferred type of dependency injection when working with immutable objects? Please explain.
Constructor injection — it's the only style that lets a dependency be assigned to a readonly field, guaranteeing it can never change after the object is constructed. Setter/property injection is inherently mutable, which directly conflicts with the goal of immutability.
Q10. How does each type of dependency injection affect the ease of unit testing?
Constructor injection makes tests explicit and safe — you can't construct the object under test without supplying (mock or real) dependencies, so there's no way to accidentally test against an unconfigured, half-set-up instance. Setter/method injection requires the test to remember to set every dependency it needs before exercising the code, and it's easy to forget one and get a confusing null-reference failure instead of a clear "missing dependency" compile error.
Enjoyed this?
Let's talk about building something together.