Master technical and career interviews with structured answers—short definition, real examples, pitfalls, and how to answer in 60–90 seconds.
Short answer: To ensure subclasses follow LSP: Subclasses should not override behavior in a way that breaks expected behavior. Explain a bit more Subclasses should preserve the invariants and preconditions/postconditions…
Short answer: 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…
Short answer: The Interface Segregation Principle (ISP) states that: Clients should not be forced to depend on interfaces they do not use. This means that interfaces should be small and focused, containing only the metho…
Short answer: 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 reusab…
Short answer: 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 in…
Short answer: Violation Example: public interface IWorker Example code { void Work(); void Eat(); void Sleep(); } public class Robot : IWorker { public void Work() { /* logic */ } public void Eat() { throw new NotImpleme…
Short answer: Refactored Using ISP: public interface IWorkable Example code { void Work(); } public interface IFeedable { void Eat(); } public interface ISleepable { void Sleep(); } public class Human : IWorkable, IFeeda…
Short answer: The Dependency Inversion Principle (DIP) states that: High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should…
Short answer: Aspect Dependency Inversion Principle (DIP) Dependency Injection (DI) Definitio A design principle about depending on abstractions A technique for passing dependencies Goal Decouple high-level logic from lo…
Short answer: 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 w…
Short answer: ❌ Without DIP (Tightly Coupled): public class FileLogger Example code { public void Log(string message) => Console.WriteLine("File log: " + message); } public class OrderService { private reado…
Short answer: ✅ 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…
Short answer: 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…
Short answer: The Unit of Work coordinates multiple Repositories and commits changes in a single transaction. For example: public interface IUnitOfWork : IDisposable Example code { IProductRepository Products { get; } IO…
Short answer: 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. Us…
Short answer: And why? The Mediator Pattern centralizes communication between components, preventing direct dependencies and reducing complexity. It promotes loose coupling and simplifies interactions. Alternatively, the…
Short answer: The Mediator Pattern centralizes communication between components, preventing direct dependencies and reducing complexity. It promotes loose coupling and simplifies interactions. Alternatively, the Observer…
Short answer: 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 a…
Short answer: 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 en…
Short answer: 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 (IS…
Short answer: 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 l…
Short answer: 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 fu…
Short answer: 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 Fact…
Short answer: ASP.NET Core MVC has built-in support for Dependency Injection. Explain a bit more Register services in Startup.cs within ConfigureServices method using IServiceCollection: public void ConfigureServices(ISe…
Short answer: 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 res…
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: To ensure subclasses follow LSP: Subclasses should not override behavior in a way that breaks expected behavior.
Subclasses should preserve the invariants and preconditions/postconditions of the base class. Avoid overriding methods to throw exceptions for valid base class behavior. Use composition over inheritance if a subclass doesn’t strictly conform to the base class behavior. Write unit tests to verify that the subclass behaves identically to the base class in all valid scenarios. ✅ Ask yourself: Can this subclass be used anywhere the base class is used — without surprises?
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: 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)
Open/Closed in ShopNest: add a new payment method by adding a class, not by editing a giant switch in CheckoutService.
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: The Interface Segregation Principle (ISP) states that: Clients should not be forced to depend on interfaces they do not use. This means that interfaces should be small and focused, containing only the methods that are relevant to the implementing class. It prevents "fat" or "bloated" interfaces.
Patterns in ShopNest should solve a real pain (swappable payments, test seams)—not be added for decoration.
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: 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 readability In contrast, large interfaces force classes to implement methods they may not need — leading to fragile and cluttered code.
Patterns in ShopNest should solve a real pain (swappable payments, test seams)—not be added for decoration.
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: 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 Making interfaces easier to mock or stub in unit tests Encouraging clean, modular design Smaller interfaces result in lower coupling and better maintainability.
Open/Closed in ShopNest: add a new payment method by adding a class, not by editing a giant switch in CheckoutService.
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: 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.
Open/Closed in ShopNest: add a new payment method by adding a class, not by editing a giant switch in CheckoutService.
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: 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)
Open/Closed in ShopNest: add a new payment method by adding a class, not by editing a giant switch in CheckoutService.
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: The Dependency Inversion Principle (DIP) states that: High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions. In other words: High-level business logic shouldn't depend on concrete implementations. Instead, both high- and low-level components should depend on interfaces or abstract classes.
Patterns in ShopNest should solve a real pain (swappable payments, test seams)—not be added for decoration.
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: Aspect Dependency Inversion Principle (DIP) Dependency Injection (DI) Definitio A design principle about depending on abstractions A 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.
Open/Closed in ShopNest: add a new payment method by adding a class, not by editing a giant switch in CheckoutService.
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: 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/stubs Promote extensibility and maintainability Serve as contracts that both high- and low-level modules depend on
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: ❌ 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."); }
} OrderService is tightly coupled to FileLogger. ✅ 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.
Open/Closed in ShopNest: add a new payment method by adding a class, not by editing a giant switch in CheckoutService.
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: ✅ 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 logic Promotes reuse — abstractions can be used across different modules Supports SOLID architecture — especially when combined with DI and IoC containers Advanced & Scenario-Based Questions
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: 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
Short answer: 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
Short answer: 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 mocking tools (e.g., Microsoft Fakes) if refactoring isn't possible. Avoid static state to improve testability.
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: And 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. Real-world… example…… (ShopNest) Patterns in ShopNest should solve a real pain…
(swappable payments, test seams)—not be added for decoration.
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: 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.
Patterns in ShopNest should solve a real pain (swappable payments, test seams)—not be added for decoration.
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: 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
Short answer: 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.
ShopNest payment fees use Strategy: IFeeCalculator with UPI/Card implementations chosen at runtime.
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: 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 inheritance hierarchies to maintain LSP. Inject dependencies instead of direct instantiation. Incrementally refactor with unit tests to ensure behavior remains consistent.
Open/Closed in ShopNest: add a new payment method by adding a class, not by editing a giant switch in CheckoutService.
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: 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.
Open/Closed in ShopNest: add a new payment method by adding a class, not by editing a giant switch in CheckoutService.
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: 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.
Patterns in ShopNest should solve a real pain (swappable payments, test seams)—not be added for decoration.
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: 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 Strategy patterns to instantiate plugins. Keep core system closed for modification but open for extension (OCP). Separate cross-cutting concerns externally. Practical .NET Questions
Open/Closed in ShopNest: add a new payment method by adding a class, not by editing a giant switch in CheckoutService.
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: 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) { services.AddControllersWithViews(); services.AddScoped<IProductService, ProductService>(); // Example } Inject dependencies via constructor injection in controllers or services: 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.
Patterns in ShopNest should solve a real pain (swappable payments, test seams)—not be added for decoration.
Design Patterns & SOLID Design Patterns in C# · SOLID
Short answer: 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 provides instances of registered services at runtime. It uses the registrations to create and inject dependencies.
Patterns in ShopNest should solve a real pain (swappable payments, test seams)—not be added for decoration.
Install Toolliyo like an app Free
Home-screen access to tutorials, coding practice & career tools — no app store needed.
On iPhone/iPad: tap Share then Add to Home Screen.