Master technical and career interviews with structured answers—short definition, real examples, pitfalls, and how to answer in 60–90 seconds.
LSP is fundamentally about correct use of inheritance. While inheritance allows code reuse, LSP ensures that the behavior of subclasses remains consistent with that of the base class. If a subclass changes the meaning or…
Answer: No client should be forced to implement methods it does not use. Break large interfaces into smaller, focused interfaces. What interviewers expect A clear definition tied to SOLID in Design Patterns & SOLID p…
Small, specific interfaces: Promote separation of concerns Make classes easier to implement and test Reduce the risk of breaking changes Avoid forcing classes to implement irrelevant methods Increase reusability and read…
ISP improves code flexibility by: Allowing classes to only depend on what they actually use Making it easier to extend or replace functionality without affecting unrelated parts Enabling composition over inheritance Maki…
Violation Example: public interface IWorker { void Work(); void Eat(); void Sleep(); } public class Robot : IWorker { public void Work() { /* logic */ } public void Eat() { throw new NotImplementedException(); } public v…
Refactored Using ISP: public interface IWorkable { void Work(); } public interface IFeedable { void Eat(); } public interface ISleepable { void Sleep(); } public class Human : IWorkable, IFeedable, ISleepable { public vo…
The Dependency Inversion Principle (DIP) states that: High-level modules should not depend on low-level modules. Both should depend on abstractions. bstractions should not depend on details. Details should depend on bstr…
Aspect Dependency Inversion Principle (DIP) Dependency Injection (DI) Definitio design principle about depending on bstractions technique for passing dependencies Goal Decouple high-level logic from low-level details Pro…
Abstractions (e.g., interfaces or abstract classes): Decouple components so changes in one don’t ripple through others Enable substitution of different implementations easily Allow for easier unit testing with mocks/stub…
❌ Without DIP (Tightly Coupled): public class FileLogger { public void Log(string message) => Console.WriteLine("File log: " + message); } public class OrderService { private readonly FileLogger _logger = new FileLogg…
✅ Key Benefits: Decouples components — changes in low-level modules won’t affect high-level ones Improves testability — you can easily inject mocks/stubs Enhances flexibility — swap implementations without touching core…
Design patterns provide structured, reusable solutions that embody SOLID principles. For example, the Strategy pattern supports OCP by allowing behavior extension without modifying existing code; Repository separates dat…
The Unit of Work coordinates multiple Repositories and commits changes in a single transaction. For example: public interface IUnitOfWork : IDisposable { IProductRepository Products { get; } IOrderRepository Orders { get…
Testing singletons/statics is tricky due to global state. Best practices include: Refactor to use interfaces and DI instead of static/singletons. Wrap static calls behind interfaces so you can mock them. Use specialized…
nd why? The Mediator Pattern centralizes communication between components, preventing direct dependencies and reducing complexity. It promotes loose coupling and simplifies interactions. Alternatively, the Observer Patte…
The Mediator Pattern centralizes communication between components, preventing direct dependencies and reducing complexity. It promotes loose coupling and simplifies interactions. Alternatively, the Observer Pattern enabl…
Define a common interface, e.g., IPaymentStrategy with a method Pay(). Implement concrete strategies for each payment method (CreditCard, PayPal, etc.). Use a context class to invoke the selected strategy at runtime, ena…
DAO (Data Access Object) focuses on low-level database operations and CRUD, typically mapping tables to objects. Repository abstracts data access at the domain level, working with aggregates/entities and encapsulating bu…
Identify classes violating SRP and break them down. Introduce abstractions and interfaces to decouple components (DIP). Replace conditional logic with polymorphism to respect OCP. Split large interfaces (ISP). Check inhe…
Use AOP (Aspect-Oriented Programming) techniques or design patterns like Decorator to separate cross-cutting concerns from business logic. In .NET, middleware, filters, or interceptors can manage concerns like logging or…
DI containers use reflection to inspect constructors of requested services, resolve dependencies recursively from their registrations, apply lifecycle scopes (Singleton, Scoped, Transient), and build the full object grap…
Define plugin contracts with interfaces (DIP). Load plugins dynamically using reflection or MEF. Use DI to inject dependencies into plugins. Ensure plugins follow SRP with focused responsibilities. Use Factory or Strateg…
ASP.NET Core MVC has built-in support for Dependency Injection. Register services in Startup.cs within ConfigureServices method using IServiceCollection: public void ConfigureServices(IServiceCollection services) { servi…
IServiceCollection: A container used during app startup to register services and their lifetimes (Scoped, Transient, Singleton). It acts as a service registry. IServiceProvider: The built container that resolves and prov…
Register DbContext with DI in Startup.cs: services.AddDbContext<AppDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConne ction"))); Implement Repositories for entities inject…
Design Patterns & SOLID Design Patterns in C# · SOLID
LSP is fundamentally about correct use of inheritance. While inheritance allows code
reuse, LSP ensures that the behavior of subclasses remains consistent with that of the
base class.
If a subclass changes the meaning or violates the expectations of the base class’s
behavior, it's misusing inheritance.
Interface Segregation Principle (ISP)Design Patterns & SOLID Design Patterns in C# · SOLID
Answer: No client should be forced to implement methods it does not use. Break large interfaces into smaller, focused interfaces.
In a production Design Patterns & SOLID application, teams apply this when handling user-facing features or integration boundaries. For example, you might use it during a sprint where reliability and observability matter—logging metrics, validating edge cases, and documenting the decision in an ADR so future developers understand why the approach was chosen.
Tip: Practice aloud on Toolliyo mock interview or the Interview Q&A section before your real interview.
Design Patterns & SOLID Design Patterns in C# · SOLID
Small, specific interfaces:
In contrast, large interfaces force classes to implement methods they may not need —
leading to fragile and cluttered code.
Design Patterns & SOLID Design Patterns in C# · SOLID
ISP improves code flexibility by:
Smaller interfaces result in lower coupling and better maintainability.
Design Patterns & SOLID Design Patterns in C# · SOLID
Violation Example:
public interface IWorker
{
void Work();
void Eat();
void Sleep();
}
public class Robot : IWorker
{
public void Work() { /* logic */ }
public void Eat() { throw new NotImplementedException(); }
public void Sleep() { throw new NotImplementedException(); }
}
❌ Robot is forced to implement Eat() and Sleep(), which don’t make sense for it.
Design Patterns & SOLID Design Patterns in C# · SOLID
Refactored Using ISP:
public interface IWorkable
{
void Work();
}
public interface IFeedable
{
void Eat();
}
public interface ISleepable
{
void Sleep();
}
public class Human : IWorkable, IFeedable, ISleepable
{
public void Work() { }
public void Eat() { }
public void Sleep() { }
}
public class Robot : IWorkable
{
public void Work() { }
}
✅ Now each class implements only the interfaces it needs — in line with ISP.
Inversion Principle (DIP)
Design Patterns & SOLID Design Patterns in C# · SOLID
The Dependency Inversion Principle (DIP) states that:
High-level modules should not depend on low-level modules. Both should
depend on abstractions.
bstractions should not depend on details. Details should depend on
bstractions.
In other words:
bstract classes.
Design Patterns & SOLID Design Patterns in C# · SOLID
Aspect Dependency Inversion Principle (DIP) Dependency Injection (DI)
Definitio
design principle about depending on
bstractions
technique for passing
dependencies
Goal Decouple high-level logic from low-level
details
Provide dependencies to
objects
Relation DIP motivates the need for DI DI is a way to implement DIP
Focus What to depend on (abstractions) How dependencies are supplied
✅ DIP is a design principle, while DI is a design pattern/technique to implement that
principle.
Design Patterns & SOLID Design Patterns in C# · SOLID
Abstractions (e.g., interfaces or abstract classes):
Design Patterns & SOLID Design Patterns in C# · SOLID
❌ Without DIP (Tightly Coupled):
public class FileLogger
{
public void Log(string message) => Console.WriteLine("File log:
" + message);
}
public class OrderService
{
private readonly FileLogger _logger = new FileLogger();
public void ProcessOrder()
{
// Logic
_logger.Log("Order processed.");
}
}
✅ With DIP (Loosely Coupled via Abstraction):
public interface ILogger
{
void Log(string message);
}
public class FileLogger : ILogger
{
public void Log(string message) => Console.WriteLine("File log:
" + message);
}
public class OrderService
{
private readonly ILogger _logger;
public OrderService(ILogger logger)
{
_logger = logger;
}
public void ProcessOrder()
{
// Logic
_logger.Log("Order processed.");
}
}
Now OrderService depends on the abstraction (ILogger), not the concrete
FileLogger. You can easily substitute with DatabaseLogger, ConsoleLogger, or a
mock in tests.
Design Patterns & SOLID Design Patterns in C# · SOLID
✅ Key Benefits:
ones
containers
dvanced & Scenario-Based
Questions
Design Patterns & SOLID Design Patterns in C# · SOLID
Design patterns provide structured, reusable solutions that embody SOLID principles. For
example, the Strategy pattern supports OCP by allowing behavior extension without
modifying existing code; Repository separates data access (SRP); Dependency Injection
supports DIP by decoupling high- and low-level modules. Using patterns helps keep code
clean, modular, and maintainable.
Design Patterns & SOLID Design Patterns in C# · SOLID
The Unit of Work coordinates multiple Repositories and commits changes in a single
transaction. For example:
public interface IUnitOfWork : IDisposable
{
IProductRepository Products { get; }
IOrderRepository Orders { get; }
int Complete();
}
public class UnitOfWork : IUnitOfWork
{
private readonly DbContext _context;
public IProductRepository Products { get; }
public IOrderRepository Orders { get; }
public UnitOfWork(DbContext context)
{
_context = context;
Products = new ProductRepository(_context);
Orders = new OrderRepository(_context);
}
public int Complete() => _context.SaveChanges();
public void Dispose() => _context.Dispose();
}
This ensures atomic commits across repositories.
Design Patterns & SOLID Design Patterns in C# · SOLID
Testing singletons/statics is tricky due to global state. Best practices include:
Design Patterns & SOLID Design Patterns in C# · SOLID
nd why?
The Mediator Pattern centralizes communication between components, preventing direct
dependencies and reducing complexity. It promotes loose coupling and simplifies
interactions. Alternatively, the Observer Pattern enables event-driven decoupling, and
Facade Pattern provides a simplified interface to complex subsystems.
Design Patterns & SOLID Design Patterns in C# · SOLID
The Mediator Pattern centralizes communication between components, preventing direct
dependencies and reducing complexity. It promotes loose coupling and simplifies
interactions. Alternatively, the Observer Pattern enables event-driven decoupling, and
Facade Pattern provides a simplified interface to complex subsystems.
Design Patterns & SOLID Design Patterns in C# · SOLID
Define a common interface, e.g., IPaymentStrategy with a method Pay(). Implement
concrete strategies for each payment method (CreditCard, PayPal, etc.). Use a context class
to invoke the selected strategy at runtime, enabling easy extension without modifying
existing code.
Design Patterns & SOLID Design Patterns in C# · SOLID
DAO (Data Access Object) focuses on low-level database operations and CRUD, typically
mapping tables to objects.
Repository abstracts data access at the domain level, working with aggregates/entities and
encapsulating business logic. Repository often uses DAO internally but is more aligned with
domain-driven design.
Design Patterns & SOLID Design Patterns in C# · SOLID
Design Patterns & SOLID Design Patterns in C# · SOLID
Use AOP (Aspect-Oriented Programming) techniques or design patterns like Decorator
to separate cross-cutting concerns from business logic. In .NET, middleware, filters, or
interceptors can manage concerns like logging or authorization, keeping SRP intact.Design Patterns & SOLID Design Patterns in C# · SOLID
DI containers use reflection to inspect constructors of requested services, resolve
dependencies recursively from their registrations, apply lifecycle scopes (Singleton, Scoped,
Transient), and build the full object graph to return fully constructed instances.
Design Patterns & SOLID Design Patterns in C# · SOLID
Practical .NET Questions
Design Patterns & SOLID Design Patterns in C# · SOLID
ASP.NET Core MVC has built-in support for Dependency Injection.
IServiceCollection:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddScoped<IProductService, ProductService>(); //
Example
}
public class HomeController : Controller
{
private readonly IProductService _productService;
public HomeController(IProductService productService)
{
_productService = productService;
}
public IActionResult Index()
{
var products = _productService.GetAll();
return View(products);
}
}
The framework resolves and injects dependencies automatically.
Design Patterns & SOLID Design Patterns in C# · SOLID
their lifetimes (Scoped, Transient, Singleton). It acts as a service registry.
registered services at runtime. It uses the registrations to create and inject
dependencies.
Design Patterns & SOLID Design Patterns in C# · SOLID
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConne
ction")));
on the DbContext:
public interface IUnitOfWork : IDisposable
{
IProductRepository Products { get; }
int Complete();
}
public class UnitOfWork : IUnitOfWork
{
private readonly AppDbContext _context;
public IProductRepository Products { get; private set; }
public UnitOfWork(AppDbContext context)
{
_context = context;
Products = new ProductRepository(_context);
}
public int Complete() => _context.SaveChanges();
public void Dispose() => _context.Dispose();
}
Register UnitOfWork in DI container as Scoped.