Interview Questions and Answers on C# (2025)
Here are some common C# interview questions along with their answers to help you prepare:
Basic Questions
1. What is C#?
- Answer: C# is a modern, object-oriented programming language developed by Microsoft as part of its .NET initiative. It's used for building a variety of applications, including web, mobile, desktop, and gaming.
2. What are the main features of C#?
- Answer: Key features of C# include:
- Strongly typed language
- Object-oriented
- Robust memory management by using automatic garbage collection
- Support for asynchronous programming
- Rich Class Libraries
- Language Integrated Query (LINQ) for data access
3. What is the difference between value types and reference types?
- Answer: Value types store the actual data and are allocated on the stack (e.g., `int`, `float`, `struct`). Reference types store a reference to the memory location where the data is stored and are allocated on the heap (e.g., `class`, `string`, `array`).
Intermediate Questions
4. What is a delegate in C#?
- Answer: A delegate is a type that defines a method signature and can hold references to methods with a matching signature. Delegates are used to implement event handling and the callback methods.
5. What are the different types of collections in C#?
- Answer: C# provides several types of collections:
- Arrays: Fixed-size data structures.
- List<T>: A dynamic array or list of items.
- Dictionary<TKey, TValue>: A collection of key/value pairs.
- HashSet<T>: A collection of unique elements.
- Queue<T>: A first-in, first-out collection.
- Stack<T>: A last-in, first-out collection.
6. Explain the concept of inheritance in C#.
- Answer: Inheritance is an object-oriented programming principle that allows a class (child class) to inherit properties and methods from another class (parent class). It promotes code reusability and establishes a natural hierarchy between classes.
Advanced Questions
7. What is the difference between `abstract class` and `interface`?
- Answer:
- An abstract class can contain implementation (methods with bodies), fields, and constructors. A derived class can inherit from an abstract class and may override its abstract members.
- An interface only contains method signatures (methods without bodies) and properties. A class or structure can implement multiple interfaces, whereas it can only inherit from one abstract class.
8. What is polymorphism in C#?
- Answer: Polymorphism is an OOP concept that allows methods to do different things based on the object that it is acting upon. In C#, it can be achieved through:
- Method overriding (runtime polymorphism).
- Method overloading (compile-time polymorphism).
9. What is LINQ and how is it used in C#?
- Answer: LINQ (Language Integrated Query) is a query syntax in C# that allows developers to perform queries on collections, databases, XML, and more, using a unified syntax. It simplifies data manipulation and retrieval, enabling the use of SQL-like queries directly within C# code.
Miscellaneous Questions
10. What is garbage collection in C#?
- Answer: Garbage collection is an automatic memory management feature in C#. The garbage collector (GC) reclaims memory occupied by objects that are no longer in use, thus preventing memory leaks and improving application performance.
11. How do you handle exceptions in C#?
- Answer: Exceptions in C# are handled using try, catch, and finally blocks. The code that may throw an exception is placed in the try block, catch blocks handle the exceptions, and the finally block contains code that runs regardless of whether an exception is thrown or caught.
12. Explain the concept of asynchronous programming in C#.
- Answer: Asynchronous programming in C# allows methods to run in the background while allowing the main thread to continue executing. The `async` and `await` keywords are used to define and call asynchronous methods, improving application responsiveness, especially in I/O-bound operations.
Conclusion
Remember to tailor your responses to reflect your knowledge and experiences, and be prepared to provide examples or elaborate on your answers during the interview. Good luck!
Here are some advanced interview questions and their answers related to C#:
1. What are the differences between `IEnumerable` and `IQueryable`?
Answer:
- `IEnumerable<T>` is optimized for in-memory operations. It pulls data from a collection, processes it on the client-side, and works with in-memory collections like Lists or Arrays.
- `IQueryable<T>` is optimized for querying data from external data sources such as databases. It does not execute the query until you enumerate it (e.g., using `ToList()`, `ToArray()`, etc.). `IQueryable` translates the expression tree into a query language (like SQL for databases), allowing for deferred execution and better performance when working with huge datasets.
2. What is the purpose of the `async` and `await` keywords in C#?
Answer:
- The `async` keyword is used to declare that a method is asynchronous. It enables the method to run asynchronously, allowing other tasks to run without blocking the calling thread.
- The `await` keyword is used to pause the execution of the async method until the awaited task completes. It does not block the thread while waiting, thus improving performance, especially in UI applications where responsiveness is essential.
3. Explain the concept of Dependency Injection and its benefits in C#.
Answer:
- Dependency Injection (DI) is a design pattern used to implement Inversion of Control (IoC), allowing for better separation of concerns and making code more testable and maintainable. It involves providing an object its dependencies rather than hard-coding them within the object.
Benefits of Dependency Injection:
- Improved Code Maintainability: Dependencies can be swapped out without modifying the dependent code.
- Easier Unit Testing: Dependencies can be mocked or stubbed when testing.
- Loose Coupling: The system becomes more flexible and less prone to issues caused by tightly bound components.
4. What are extension methods in C# and how are they implemented?
Answer:
- Extension methods allow you to add new methods to existing types without modifying the original type or creating a derived type. They provide a way to "extend" the functionality of the class.
Implementation:
1. Create a static class to contain your extension method.
2. Define a static method with the `this` keyword before the first parameter, which indicates the type you are extending.
```csharp
public static class StringExtensions
{
public static bool IsNullOrEmpty(this string str)
{
return string.IsNullOrEmpty(str);
}
}
```
5. What is garbage collection in C#? How does it work?
Answer:
- Garbage collection (GC) is the automatic memory management feature in C#. It automatically releases memory that is no longer in use, preventing memory leaks and optimizing memory usage.
How it works:
1. The GC runs when the system is low on memory or at specific intervals.
2. It tracks the references to objects in memory.
3. It identifies objects that are no longer reachable (i.e., no references are pointing to them).
4. It then releases that memory, allowing it to be reused.
6. What is the difference between a `struct` and a `class` in C#?
Answer:
- Allocation: Classes are reference types, meaning they are allocated on the heap and accessed via references. Structs are value types and are allocated on the stack (unless they are part of a heap-allocated object).
- Handling & Performance: Since structs are copied by value, they can lead to performance overhead if large structs are used frequently. Classes, being reference types, only require a reference to be passed around.
- Inheritance: Classes support inheritance; structs do not. You cannot inherit from a struct, but you can implement interfaces.
7. What is the purpose of `lock` statement in C#?
Answer:
- The `lock` statement is used to ensure that a block of code runs by only one thread at a time. It is a way to deal with race conditions in multi-threaded applications. By locking an object, other threads are prevented from entering a critical section of code until the lock is released.
```csharp
private readonly object _lock = new object();
public void ThreadSafeMethod()
{
lock (_lock)
{
// Critical section code goes here...
}
}
```
8. What is the difference between `override` and `new` keywords in method definitions?
Answer:
- The `override` keyword is used in a derived class to provide a specific implementation of a method that is already defined in its base class. The base class method must be marked with the `virtual` or `abstract` keyword.
- The `new` keyword is used to hide a method in the base class. The base method stays unchanged and can still be accessed via the base class reference.
```csharp
class BaseClass
{
public virtual void Display() { Console.WriteLine("Base Display"); }
}
class DerivedClass : BaseClass
{
public override void Display() { Console.WriteLine("Derived Display"); }
}
class AnotherDerivedClass : BaseClass
{
public new void Display() { Console.WriteLine("Another Derived Display"); }
}
```
9. How does C# implement immutability and what are its benefits?
Answer:
- Immutability in C# can be achieved using `readonly` fields or by creating immutable types using properties or structures that do not provide setters. If the object's state cannot be changed after it's created, it is considered immutable.
Benefits of Immutability:
- Thread Safety: Immutable objects are inherently thread-safe. Multiple threads can safely read without locks.
- Easier to Reason About: Since they do not change state, the behavior of the application becomes more predictable.
- Improved Performance: The use of immutable objects can lead to reduced overhead in scenarios involving concurrency and caching.
10. What are tuples in C# and how can they be used?
Answer:
- Tuples are data structures that can hold a fixed size collection of heterogeneously typed items. They can be defined using the `ValueTuple` type.
Usage:
You can create tuples to return multiple values from a method easily.
```csharp
public (int, string) GetPersonInfo()
{
return (1, "John Doe");
}
var person = GetPersonInfo();
Console.WriteLine($"ID: {person.Item1}, Name: {person.Item2}");
```
Starting from C# 7.0, tuples are more user-friendly with named elements, allowing for better readability:
```csharp
public (int Id, string Name) GetPersonInfo() => (1, "John Doe");
var (id, name) = GetPersonInfo();
Console.WriteLine($"ID: {id}, Name: {name}");
```
These questions and answers cover various aspects of C# and should help you prepare for an advanced interview effectively.
Scenario-Based C# Interview Questions and Answers
1.Scenario: Implementing Dependency Injection in a .NET Application
Q: How would you use Dependency Injection (DI) to manage object lifetimes in a large-scale C# application?
Answer:
In a large-scale .NET application, I use the built-in
Microsoft.Extensions.DependencyInjection framework. For example:
csharp
CopyEdit
public
interface
IEmailService {
void
SendEmail(
string to,
string subject,
string body);
}
public
class
EmailService :
IEmailService {
public
void
SendEmail(
string to,
string subject,
string body) {
// SMTP logic
}
}
In Program.cs
or Startup.cs
:
csharp
CopyEdit
services.AddScoped<IEmailService,
EmailService>();
Here:
AddSingleton
– for shared instances (like configuration).
AddScoped
– for per-request lifetimes (e.g., database
context).
AddTransient
– for lightweight, stateless services.
Queries: C# dependency injection interview question, DI in ASP.NET Core
2. Scenario:Managing Memory with IDisposable
Q: You are working with unmanaged resources in C#. How do you ensure proper memory management?
Answer:
Implement the IDisposable
interface using the dispose pattern:
csharp
CopyEdit
public
class
FileManager :
IDisposable {
private FileStream _fileStream;
private
bool _disposed =
false;
public
FileManager(
string filePath) {
_fileStream =
new FileStream(filePath,
FileMode.Open);
}
public
void
Dispose() {
Dispose(
true);
GC.SuppressFinalize(
this);
}
protected
virtual
void
Dispose(
bool disposing) {
if (!_disposed) {
if (disposing) {
_fileStream?.Dispose();
}
_disposed =
true;
}
}
~FileManager() {
Dispose(
false);
}
}
Queries: IDisposable C# example, memory management in C#,garbage collection
3. Scenario:Handling Exceptions in Asynchronous Code
Q: How do you handle exceptions in async
/await
methods
in C#?
Answer: You handle them using try-catch just like synchronous code:
csharp
CopyEdit
public
async Task<
string>
GetDataAsync(
string url) {
try {
using HttpClient client =
new HttpClient();
return
await client.GetStringAsync(url);
}
catch (HttpRequestException ex) {
// Log and handle error
return
$"Error: {ex.Message}";
}
}
Also, Task.WhenAll
must be wrapped in try-catch if aggregating tasks:
csharp
CopyEdit
try {
await Task.WhenAll(task1, task2);
}
catch (Exception ex) {
// Handle aggregate exception
}
Queries: exception handling in async await C#, async exception scenario
4. Scenario:Performance Optimization in LINQ
Q: LINQ is slowing down your application. How would you optimize it?
Answer: Avoid using ToList()
or ToArray()
too early (deferred execution).
Use AsParallel()
only if CPU-bound and thread-safe.
Replace .Where(...).FirstOrDefault()
with .FirstOrDefault(...)
for efficiency.
Use compiled queries for EF Core:
csharp
CopyEdit
var compiledQuery =
EF.CompileQuery((DbContext db,
int id) =>
db.Users.FirstOrDefault(u => u.Id ==
id));
Queries: LINQ performance tips C#, optimize LINQ queries, EF Core compiled query.
5. Scenario:Multithreading and Data Race Conditions
Q: You have multiple threads accessing a shared resource. How do you prevent data races in C#?
Answer: Use locking mechanisms:
csharp
CopyEdit
private
static
readonly
object _lock =
new
object();
public
void
IncrementCounter() {
lock (_lock) {
_counter++;
}
}
Or use concurrent collections:
csharp
CopyEdit
ConcurrentDictionary<
string,
int> dict =
new ConcurrentDictionary<
string,
int>();
dict.TryAdd(
"key",
1);
Use SemaphoreSlim
for async-compatible locking.
Queries: C# thread safety, data race condition C#, lock vs ConcurrentDictionary
6. Scenario:Real-Time Notifications in ASP.NET Core
Q: How would you implement real-time notifications in a web application using C#?
Answer:
Use SignalR:
csharp
CopyEdit
public
class
NotificationHub :
Hub {
public
async Task
SendNotification(
string message) {
await Clients.All.SendAsync(
"ReceiveMessage", message);
}
}
In Startup.cs
:
csharp
CopyEdit
services.AddSignalR();
app.UseEndpoints(endpoints
=> {
endpoints.MapHub<NotificationHub>(
"/notify");
});
Queries: SignalR real-time C#, ASP.NET Core notifications
7. Scenario:Building a Thread-Safe Singleton in C#
Q: How do you implement a thread-safe singleton pattern in C#?
Answer:
Using lazy initialization:
csharp
CopyEdit
public
sealed
class
Singleton {
private
static
readonly Lazy<Singleton> _instance =
new Lazy<Singleton>(() =>
new Singleton());
public
static Singleton Instance => _instance.Value;
private
Singleton() { }
}
This is lazy, thread-safe,and efficient.
Queries: thread-safe singleton C#, singleton pattern C# best practice.
8. Scenario: Unit Testing a Repository with Mocking
Q: How do you unit test a repository that uses Entity Framework without hitting the database?
Answer: Use mocking frameworks like Moq:
csharp
CopyEdit
var mockSet =
new Mock<DbSet<User>>();
var mockContext =
new Mock<AppDbContext>();
mockContext.Setup(m
=> m.Users).Returns(mockSet.Object);
// Inject mockContext into repository and test methods
Or use in-memory database:
csharp
CopyEdit
var options =
new
DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase(databaseName:
"TestDB").Options;
Queries: unit test EF Core repository, mock DbSet C#, Moq EF Core
Difference Between Abstract Class and Interface in C# – Interview Questions and Answers
Q . What is the difference between an abstract class and an interface in C#? Explain with examples.
Answer:
Abstract Class in C#:
An abstract class is a class that cannot be instantiated. It can contain abstract methods (without implementation) and concrete methods (with implementation).
csharp
CopyEdit
public
abstract
class
Animal
{
public
abstract
void
MakeSound();
public
void
Eat()
{
Console.WriteLine(
"Animal is eating.");
}
}
Interface in C#:
An interface defines a contract that implementing classes must fulfill. It can only contain method signatures (until C# 8.0, after which default implementations are allowed).
csharp
CopyEdit
public
interface
IAnimal
{
void
MakeSound();
}
Comparison Table: Abstract Class vs Interface in C#
Feature |
Abstract Class |
Interface |
Inheritance |
Supports single inheritance |
Supports multiple interface inheritance |
Method Implementation |
Can have both abstract and implemented methods |
No implementation (before C# 8.0) |
Constructors |
Can have constructors |
Cannot have constructors |
Access Modifiers |
Supports public, protected, etc. |
All members are public by default |
Fields |
Can declare fields |
Cannot declare fields (only properties or constants) |
Use Case |
When base functionality is shared |
When only behavior needs to be enforced |
Pro Tip :
When to use an abstract class vs interface in C# depends on your design needs. Use an abstract class when you have shared code or a common base behavior. Use interfaces when different classes share only method signatures but not implementation.
Shape
with common code like CalculateArea()
and an interface like IDrawable
to require a Draw()
method in unrelated classes.Question:
How do you handle a null reference scenario in C#?
Answer:
In C#, a null reference exception occurs when you try to access a
member on an object that is set to null
. This is one of the most
frequent runtime errors in .NET applications, especially in large-scale
enterprise systems. Handling it properly ensures application stability and
improves code quality. Here are several effective ways to handle and prevent
null reference scenarios in C#:
1. Use Null Checks
Perform a null check before accessing the object or its members.
csharp
CopyEdit
if (employee !=
null)
{
Console.WriteLine(employee.Name);
}
This is the most straightforward way to avoid a NullReferenceException
.
2. Use Null-Conditional Operator (?.
)
Introduced in C# 6.0, the null-conditional operator allows you to safely access members without throwing an exception if the object is null.
csharp
CopyEdit
Console.WriteLine(employee?.Name);
This prevents the application from crashing if employee
is null.
3. Use Null-Coalescing Operator (??
)
This operator allows you to assign a default value if an object or expression evaluates to null.
csharp
CopyEdit
string name = employee?.Name ??
"Unknown";
4. Enable Nullable Reference Types (C# 8.0+)
With C# 8.0, you can enable nullable reference types to get compile-time warnings for potential null assignments and usage.
csharp
CopyEdit
#nullable enable
public
string? MiddleName {
get;
set; }
This helps you write safer code by explicitly handling possible nulls.
5. Implement Guard Clauses
Guard clauses are used to validate input arguments and fail fast when a null is detected.
csharp
CopyEdit
public
void
Process(
Employee employee)
{
if (employee ==
null)
throw
new ArgumentNullException(
nameof(employee));
}
Sample Interview Response:
“To handle null reference scenarios in C#, I apply multiple strategies. For
general access, I use null checks or the null-conditional operator (?.
). When assigning fallback values, I
use the null-coalescing operator (??
).
In methods, I apply guard clauses to ensure input parameters are not null.
Additionally, I enable nullable reference types in C# 8.0 and above to detect
nullability issues at compile time. This helps me write robust, error-resistant
code.”
Answers:
A real-time use case for delegates in C# is implementing event-driven programming, such as in GUI applications or real-time data processing systems. For example, in a stock trading application, delegates can be used to handle real-time stock price updates. When new data arrives, a delegate can invoke multiple subscribed event handlers simultaneously to update the user interface, log data, or trigger alerts. This approach allows for flexible, efficient, and decoupled code, enabling responsive and scalable applications that react promptly to live data changes. Using delegates in such scenarios enhances code maintainability and performance by enabling dynamic method invocation and event management in real-time systems.
Q. How do you manage state in a multithreaded C# application?
Managing state in a multithreaded C# application is crucial to avoid race conditions, deadlocks, and data inconsistency. In .NET, there are several best practices and thread-safe constructs designed to ensure reliable state management across multiple threads.
1. Use Locking with lock
Statement
The lock
keyword ensures
that only one thread can access a critical section of code at a time.
csharp
CopyEdit
private
readonly
object _lockObj =
new
object();
private
int counter =
0;
public
void
Increment()
{
lock (_lockObj)
{
counter++;
}
}
Tip: This prevents race conditions in C# multithreaded applications.
2. Use Thread-Safe Collections
.NET provides built-in thread-safe collections like:
·
ConcurrentDictionary<TKey,
TValue>
·
ConcurrentQueue<T>
·
ConcurrentBag<T>
These are optimized for multithreaded environments and reduce the need for manual locking.
csharp
CopyEdit
ConcurrentDictionary<
int,
string> data =
new ConcurrentDictionary<
int,
string>();
data.TryAdd(
1,
"value");
3. Use Interlocked
Class for Atomic Operations
The Interlocked
class
allows atomic operations on shared variables, ideal for performance-critical
state updates.
csharp
CopyEdit
Interlocked.Increment(
ref counter);
4. Apply volatile
Keyword for Visibility
Use volatile
for fields
that are accessed by multiple threads to prevent CPU caching issues.
csharp
CopyEdit
private
volatile
bool _isRunning;
This ensures that the latest value is always read from memory.
5. Avoid Shared State Where Possible
Design your application using stateless services, message passing, or immutable objects to reduce shared state complexity and improve thread safety.
6. Use Async/Await Carefully
Although async/await
simplifies asynchronous programming, improper usage with shared resources can
still cause state issues. Always ensure thread safety when modifying shared
variables in async methods.
Sample Interview Response:
“To manage state in a multithreaded C# application, I use thread
synchronization techniques like the lock
statement and Interlocked
operations for atomic updates. I prefer ConcurrentDictionary
or other thread-safe collections when multiple threads read and write shared
data. I also minimize shared state by using immutable objects and stateless
design patterns wherever possible. This helps ensure that my applications
remain thread-safe, scalable, and maintainable.”
Managing state in multithreaded C# applications requires careful use of
synchronization primitives like lock
,
Interlocked
, and volatile
, as well as leveraging
thread-safe collections. Designing your code to reduce shared mutable state is
key to writing safe, scalable concurrent applications in .NET.
Comments
Post a Comment