Focus: Practical implementation, Clean Architecture, SOLID principles, Dependency Injection, and real-world scenarios.
1. 🔴 How do you apply the four OOP pillars in an ASP.NET Core Web API application?
The four OOP pillars are Encapsulation, Abstraction, Inheritance, and Polymorphism.
|
OOP Pillar |
ASP.NET Core Example |
|---|---|
|
Encapsulation |
Protect business data using private fields and public methods |
|
Abstraction |
Define service contracts using interfaces |
|
Inheritance |
Create common functionality in base classes |
|
Polymorphism |
Implement different behaviors using the same interface |
Real-world example: Banking Application
-
Encapsulation:
BankAccountcontrols deposits and withdrawals. -
Abstraction:
IAccountServicedefines account operations. -
Inheritance:
SavingsAccountinherits fromBankAccount. -
Polymorphism: Savings and Current accounts calculate interest differently.
Interview Key Point: OOP helps build maintainable, reusable, loosely coupled, and testable Web API applications.
2. 🔴 How do interfaces and Dependency Injection work together in ASP.NET Core?
An interface defines a contract, while Dependency Injection (DI) supplies the implementation at runtime.
Example:
public interface IUserService
{
string GetUser();
}
public class UserService : IUserService
{
public string GetUser() => "John";
}
Register in Program.cs:
builder.Services.AddScoped<IUserService, UserService>();
Inject into Controller:
public class UserController : ControllerBase
{
private readonly IUserService _service;
public UserController(IUserService service)
{
_service = service;
}
[HttpGet]
public string Get() => _service.GetUser();
}
How it works:
Controller
|
v
IUserService (Interface)
|
v
Dependency Injection Container
|
v
UserService (Implementation)
Interview Key Point: Interfaces provide abstraction; DI provides implementations without the controller creating concrete service objects.
3. 🔴 Why do we create separate Controller, Service, and Repository classes?
We separate these classes to follow the Single Responsibility Principle (SRP) and maintain Separation of Concerns.
|
Layer |
Responsibility |
|---|---|
|
Controller |
Handles HTTP requests and responses |
|
Service |
Contains business logic and validations |
|
Repository |
Handles database operations |
Example:
HTTP Request
|
v
UserController
|
v
IUserService
|
v
UserService
|
v
IUserRepository
|
v
UserRepository
|
v
SQL Server
Advantages:
-
Easy unit testing.
-
Better maintainability.
-
Reusable business logic.
-
Reduced coupling.
-
Changes in one layer have less impact on others.
Interview Key Point: Controllers handle HTTP, Services handle business rules, and Repositories handle data access. A repository layer is optional when EF Core already provides sufficient abstraction.
4. 🔴 How do you implement polymorphism in a real-world application?
Polymorphism allows different classes to provide different implementations through a common interface or base class.
Example: Notification System
public interface INotification
{
void Send();
}
public class EmailNotification : INotification
{
public void Send()
{
Console.WriteLine("Email sent");
}
}
public class SmsNotification : INotification
{
public void Send()
{
Console.WriteLine("SMS sent");
}
}
Usage:
INotification notification = new EmailNotification();
notification.Send();
notification = new SmsNotification();
notification.Send();
Output:
Email sent
SMS sent
Interview Key Point: The same method call executes different implementations depending on the actual object type. This is runtime polymorphism.
5. 🔴 How would you design multiple payment methods using interfaces and polymorphism?
I would use the Strategy Pattern, where each payment method implements a common interface.
Step 1: Create interface
public interface IPaymentService
{
void Pay(decimal amount);
}
Step 2: Implement payment methods
public class UpiPayment : IPaymentService
{
public void Pay(decimal amount)
{
Console.WriteLine($"UPI: {amount}");
}
}
public class CardPayment : IPaymentService
{
public void Pay(decimal amount)
{
Console.WriteLine($"Card: {amount}");
}
}
Step 3: Execute payment
IPaymentService payment = new UpiPayment();
payment.Pay(1000);
payment = new CardPayment();
payment.Pay(2000);
Flow:
Payment Request
|
v
IPaymentService
|
+---- UpiPayment
|
+---- CardPayment
|
+---- NetBankingPayment
In ASP.NET Core, a payment factory or resolver can select the appropriate registered implementation based on the requested payment method.
Interview Key Point: New payment methods can be added without changing existing payment implementations, supporting the Open/Closed Principle.
6. 🔴 When would you choose an abstract class instead of an interface in a banking application?
Choose an abstract class when multiple related classes share common state, validation, and implementation.
Example:
public abstract class BankAccount
{
public decimal Balance { get; protected set; }
public void Deposit(decimal amount)
{
if (amount <= 0)
throw new ArgumentException("Invalid amount");
Balance += amount;
}
public abstract decimal CalculateInterest();
}
Derived class:
public class SavingsAccount : BankAccount
{
public override decimal CalculateInterest()
{
return Balance * 0.04m;
}
}
When to choose:
|
Abstract Class |
Interface |
|---|---|
|
Shared state and implementation |
Common contract |
|
Related account types |
Different service implementations |
|
Supports constructors |
No instance constructors |
|
Single class inheritance |
Multiple interfaces supported |
Interview Key Point: Use abstract classes for shared behavior and state; interfaces for contracts and loose coupling.
7. 🔴 How does Clean Architecture apply OOP and SOLID principles?
Clean Architecture separates the application into layers with clear responsibilities and dependencies pointing inward.
Example: ASP.NET Core Web API
Presentation (Web API)
|
v
Application
Interfaces, DTOs, Use Cases
|
v
Domain
Entities, Business Rules
Infrastructure
EF Core, SQL Server, External APIs
|
v
Application / Domain Contracts
At runtime, the Web API uses Dependency Injection to connect application interfaces to infrastructure implementations.
OOP and SOLID implementation:
|
Principle |
Clean Architecture Example |
|---|---|
|
Encapsulation |
Domain entities protect business rules |
|
Abstraction |
Application defines interfaces |
|
Polymorphism |
Different implementations of contracts |
|
SRP |
Each layer/class has a focused responsibility |
|
OCP |
Extend behavior without modifying core logic |
|
LSP |
Implementations honor their contracts |
|
ISP |
Small, focused interfaces |
|
DIP |
High-level logic depends on abstractions |
Interview Key Point: Clean Architecture combines OOP and SOLID to keep business logic independent of databases, frameworks, and external services.
8. 🟡 How do you design reusable services without tightly coupling components?
I use interfaces, Dependency Injection, and SRP to design reusable services.
Example:
public interface IEmailService
{
Task SendAsync(string email, string message);
}
public class OrderService
{
private readonly IEmailService _email;
public OrderService(IEmailService email)
{
_email = email;
}
}
Benefits:
-
OrderServicedoes not depend on a specific email provider. -
Email implementation can be replaced.
-
The service can be reused by other modules.
-
Unit tests can use mock implementations.
Interview Key Point: Depend on interfaces instead of concrete classes to achieve loose coupling and reusability.
9. 🟡 How would you refactor a large class that violates the Single Responsibility Principle?
First, identify the different responsibilities handled by the class, then extract them into focused services.
Before refactoring:
public class OrderService
{
public void CreateOrder() { }
public void ProcessPayment() { }
public void SendEmail() { }
public void GenerateInvoice() { }
}
After refactoring:
OrderService
|
+---- IPaymentService
|
+---- IEmailService
|
+---- IInvoiceService
Each service handles one responsibility.
The OrderService coordinates the workflow through injected interfaces.
Interview Key Point: Refactoring using SRP improves maintainability, testability, and reduces the impact of future changes.
10. 🟡 How do you write unit tests for classes that depend on interfaces?
We use mock objects to replace external dependencies during unit testing.
Example using xUnit and Moq:
Service:
public class UserService
{
private readonly IUserRepository _repository;
public UserService(IUserRepository repository)
{
_repository = repository;
}
public string GetName(int id)
{
return _repository.GetName(id);
}
}
Unit test:
[Fact]
public void GetName_ReturnsUserName()
{
var mock = new Mock<IUserRepository>();
mock.Setup(x => x.GetName(1))
.Returns("John");
var service = new UserService(mock.Object);
Assert.Equal("John", service.GetName(1));
}
Benefits:
-
No real database required.
-
Tests execute quickly.
-
Dependencies can be controlled.
-
Business logic can be tested independently.
Interview Key Point: Interfaces and DI make unit testing easier by allowing real dependencies to be replaced with mocks or fakes.
11. 🟡 How would you replace a long if-else or switch statement using polymorphism?
I would use the Strategy Pattern to replace conditional business logic with separate implementations.
Before:
if (type == "Email")
SendEmail();
else if (type == "SMS")
SendSMS();
else if (type == "Push")
SendPush();
After:
public interface INotification
{
void Send();
}
Implementations:
public class EmailNotification : INotification
{
public void Send() => Console.WriteLine("Email");
}
public class SmsNotification : INotification
{
public void Send() => Console.WriteLine("SMS");
}
Usage:
INotification notification = new EmailNotification();
notification.Send();
A factory or DI-based resolver selects the implementation at runtime. This may still require a small selection mechanism, but the business logic no longer depends on a growing chain of conditions.
Interview Key Point: Polymorphism replaces complex conditional behavior with extensible implementations and supports OCP.
12. 🟡 How do you decide between inheritance, composition, and Dependency Injection?
The decision depends on the relationship between classes and how dependencies should be managed.
|
Concept |
When to Use |
Example |
|---|---|---|
|
Inheritance |
IS-A relationship |
SavingsAccount IS-A BankAccount |
|
Composition |
HAS-A relationship |
OrderService HAS-A PaymentProcessor |
|
Dependency Injection |
External dependency supplied to a class |
Inject |
Inheritance:
public class SavingsAccount : BankAccount
{
}
Composition:
public class Car
{
private readonly Engine _engine = new();
}
Dependency Injection:
public class OrderService
{
private readonly IPaymentService _payment;
public OrderService(IPaymentService payment)
{
_payment = payment;
}
}
Interview Key Point:
-
Use Inheritance for genuine IS-A relationships.
-
Prefer Composition to combine functionality without rigid inheritance hierarchies.
-
Use Dependency Injection to supply dependencies externally and reduce coupling.
Dependency Injection is often a way of implementing composition, rather than an alternative to it.
Quick Interview Revision – All 12 Questions
|
# |
Topic |
Key Points to Remember |
|---|---|---|
|
1 |
Four OOP Pillars |
Encapsulation, Abstraction, Inheritance, Polymorphism |
|
2 |
Interface + DI |
Contract + Implementation + DI Container |
|
3 |
Controller / Service / Repository |
HTTP + Business Logic + Data Access |
|
4 |
Polymorphism |
Same contract, different behavior |
|
5 |
Multiple Payments |
Interface + Strategy Pattern |
|
6 |
Abstract Class vs Interface |
Shared implementation vs Contract |
|
7 |
Clean Architecture |
OOP + SOLID + Dependency Rule |
|
8 |
Reusable Services |
Interfaces + DI + Loose Coupling |
|
9 |
SRP Refactoring |
Split responsibilities into focused classes |
|
10 |
Unit Testing |
xUnit + Moq + Mock Dependencies |
|
11 |
Replace if-else |
Strategy Pattern + Polymorphism |
|
12 |
Inheritance vs Composition vs DI |
IS-A vs HAS-A vs Injected Dependency |
Explain association in C# with simple example.
Association in C#
Association is an "uses-a" relationship between two independent classes. One object can use or communicate with another object, but both objects can exist independently.
- One class knows about another class.
- There is no ownership between them.
- If one object is destroyed, the other object still exists.
Real-Life Example
A Teacher teaches a Student.
- A Teacher can exist without a Student.
- A Student can exist without a Teacher.
- They are simply associated with each other.
C# Example
using System;
public class Student
{
public string Name { get; set; }
public Student(string name)
{
Name = name;
}
}
public class Teacher
{
public string Name { get; set; }
public Teacher(string name)
{
Name = name;
}
public void Teach(Student student)
{
Console.WriteLine($"{Name} is teaching {student.Name}");
}
}
class Program
{
static void Main()
{
Student student = new Student("John");
Teacher teacher = new Teacher("David");
teacher.Teach(student);
}
}
Output
David is teaching John
Explanation
TeacherandStudentare independent classes.- The
Teacherobject only uses theStudentobject in theTeach()method. - Neither object owns the other.
- If the
Teacherobject is deleted, theStudentobject still exists. - If the
Studentobject is deleted, theTeacherobject still exists.
Another Example
A Customer places an Order.
public class Customer
{
public string Name { get; set; }
}
public class Order
{
public void PlaceOrder(Customer customer)
{
Console.WriteLine($"{customer.Name} placed an order.");
}
}
Here, Order uses Customer, but neither owns the other.
UML Representation
+---------+ Uses +---------+
| Teacher | -----------------> | Student |
+---------+ +---------+
Key Points
- Association means one object uses another object.
- It represents a "uses-a" relationship.
- Both classes are independent.
- There is no ownership.
- Association can be one-to-one, one-to-many, or many-to-many.
Interview Definition
Association is a relationship between two independent classes where one class uses or communicates with another class, but neither class owns the other. Both objects have independent lifecycles.
Aggregation in C#
Aggregation is a special type of Association that represents a "has-a" relationship with weak ownership.
The parent object contains a reference to the child object, but the child can exist independently of the parent.
- Parent has child.
- Child can exist without the parent.
- Parent does not own the child's lifetime.
Real-Life Example
A Department has Teachers.
- A Teacher can exist without a Department.
- If a Department is deleted, the Teacher still exists and can join another Department.
C# Example
using System;
using System.Collections.Generic;
public class Teacher
{
public string Name { get; set; }
public Teacher(string name)
{
Name = name;
}
}
public class Department
{
public string Name { get; set; }
public List<Teacher> Teachers { get; }
public Department(string name, List<Teacher> teachers)
{
Name = name;
Teachers = teachers;
}
public void ShowTeachers()
{
Console.WriteLine($"Department: {Name}");
foreach (var teacher in Teachers)
{
Console.WriteLine(teacher.Name);
}
}
}
class Program
{
static void Main()
{
Teacher t1 = new Teacher("David");
Teacher t2 = new Teacher("John");
List<Teacher> teachers = new List<Teacher>
{
t1,
t2
};
Department department = new Department("Computer Science", teachers);
department.ShowTeachers();
// Department object is destroyed
department = null;
// Teachers still exist
Console.WriteLine(t1.Name);
Console.WriteLine(t2.Name);
}
}
Output
Department: Computer Science
David
John
David
John
Explanation
DepartmenthasTeacherobjects.Teacherobjects are created outside theDepartment.- The
Departmentonly stores references to the teachers. - If the
Departmentobject is destroyed, theTeacherobjects still exist. - This is weak ownership.
Another Example
A Team has Players.
public class Player
{
public string Name { get; set; }
}
public class Team
{
public List<Player> Players { get; set; }
}
Even if the Team object is deleted, the Player objects can join another team.
UML Representation
+------------+ ◇--------> +---------+
| Department | | Teacher |
+------------+ +---------+
◇ = Hollow Diamond (Aggregation)
Characteristics
- Represents a Has-A relationship.
- Parent and child have independent lifecycles.
- Child objects are created externally.
- Parent stores only references to child objects.
- Also called weak ownership.
Association vs Aggregation
| Association | Aggregation |
|---|---|
| Uses-a relationship | Has-a relationship |
| No ownership | Weak ownership |
| Objects are independent | Objects are independent |
| One object uses another | Parent contains child reference |
| Example: Teacher teaches Student | Example: Department has Teachers |
Interview Definition
Aggregation is a special type of association that represents a "has-a" relationship with weak ownership. The parent contains references to child objects, but the child objects can exist independently of the parent.
Composition in C#
Composition is a special type of Aggregation that represents a "has-a" relationship with strong ownership.
The parent object owns the child object. If the parent is destroyed, the child is also destroyed.
- Parent creates the child.
- Parent owns the child.
- Child cannot exist independently.
- Child's lifetime depends on the parent.
Real-Life Example
A House has Rooms.
- A Room cannot exist without a House.
- If the House is demolished, its Rooms also cease to exist.
C# Example
using System;
public class Engine
{
public void Start()
{
Console.WriteLine("Engine Started");
}
}
public class Car
{
// Car owns the Engine
private Engine engine;
public Car()
{
engine = new Engine(); // Created inside Car
}
public void StartCar()
{
engine.Start();
Console.WriteLine("Car Started");
}
}
class Program
{
static void Main()
{
Car car = new Car();
car.StartCar();
}
}
Output
Engine Started
Car Started
Explanation
Carcreates theEngineobject usingnew Engine().- The
Engineobject is private to theCar. - No other class can directly use or share this
Engine. - If the
Carobject is destroyed, itsEngineis also destroyed. - This is strong ownership.
Another Example
A House has Rooms.
using System.Collections.Generic;
public class Room
{
public string Name { get; set; }
public Room(string name)
{
Name = name;
}
}
public class House
{
public List<Room> Rooms { get; }
public House()
{
Rooms = new List<Room>
{
new Room("Living Room"),
new Room("Bedroom"),
new Room("Kitchen")
};
}
}
Here:
Housecreates theRoomobjects.Roomobjects belong only to thatHouse.- They are not shared with another
House.
UML Representation
+------+ ◆--------> +--------+
| Car | | Engine |
+------+ +--------+
◆ = Filled Diamond (Composition)
Characteristics
- Represents a Has-A relationship.
- Strong ownership.
- Parent creates the child object.
- Child cannot exist without the parent.
- Child is usually private to the parent.
- Child is not shared with other objects.
Aggregation vs Composition
| Aggregation | Composition |
|---|---|
| Weak ownership | Strong ownership |
| Child exists independently | Child depends on parent |
| Child created outside parent | Child created inside parent |
| Child can be shared | Child is not shared |
| Parent stores reference | Parent owns the object |
| Example: Department has Teachers | Example: Car has Engine |
Association vs Aggregation vs Composition
| Feature | Association | Aggregation | Composition |
|---|---|---|---|
| Relationship | Uses-A | Has-A | Has-A |
| Ownership | No ownership | Weak ownership | Strong ownership |
| Independent lifecycle | Yes | Yes | No |
| Child created by parent | No | No | Yes |
| Child survives parent | Yes | Yes | No |
| Example | Teacher teaches Student | Department has Teachers | Car has Engine |
Interview Definition
Composition is a special type of aggregation that represents a "has-a" relationship with strong ownership. The parent creates and owns the child object, and the child cannot exist independently of the parent.
For a Senior .NET Developer / Technical Lead interview, questions 2, 3, 5, 7, 9, and 12 deserve particular attention because they test architecture decisions, maintainability, extensibility, and real-world design experience.