Chapter 3 — Advanced C# (60 Questions)
Topics:
Async & Multithreading
- How async/await works internally
- Synchronization context
- ConfigureAwait
- Deadlocks
- Thread safety
- Locks
- Monitor
- Mutex
- SemaphoreSlim
- Concurrent collections
Advanced Language Features
- Expression trees
- Reflection deep dive
- Attributes
- Dynamic keyword
- Span<T>
- Memory<T>
- Unsafe code
- Stackalloc
- Yield return
- Iterators
Performance
- Boxing optimization
- Allocation reduction
- Object pooling
- Caching strategies
- Profiling
Advanced LINQ
Enterprise C#
31–60:
- design considerations
- performance tuning
- best practices
- advanced patterns
. How does async/await work internally in C#?
Interview Answer
async and await are compiler features that simplify asynchronous programming. The compiler transforms an async method into a state machine.
Example:
public async Task<string> GetDataAsync()
{
var result = await httpClient.GetStringAsync(url);
return result;
}
The compiler converts this into a state machine that:
- Starts executing the method.
- Runs until it reaches await.
- Checks whether the task is completed.
- If not completed, returns control to the caller.
- Continues execution when the task completes.
Important Point
await does not block the thread.
While waiting for an HTTP request or database call:
- the thread is returned to the thread pool
- other requests can use that thread
This improves application scalability.
Follow-up Question
Q: Does async/await create a new thread?
Answer
No.
For I/O operations:
await database.GetDataAsync();
No new thread is usually created.
The operating system handles the I/O operation, and the application continues when the operation completes.
2. What is the difference between synchronous and asynchronous programming?
Interview Answer
Synchronous programming
Operations execute one after another.
Example:
var data = GetData();
Process(data);
The second operation waits until the first finishes.
Asynchronous programming
A long-running operation can continue without blocking execution.
Example:
var data = await GetDataAsync();
Process(data);
Comparison
Synchronous | Asynchronous |
Blocks execution | Does not block while waiting |
Simpler | More scalable |
Good for CPU operations | Good for I/O operations |
Uses fewer concepts | Requires async flow |
Senior Answer
In server applications, asynchronous programming is especially valuable because it allows handling more concurrent requests with fewer threads.
3. What is ConfigureAwait(false)?
Interview Answer
ConfigureAwait(false) tells the runtime not to capture the current synchronization context after awaiting.
Example:
await service.GetDataAsync()
.ConfigureAwait(false);
Why does this matter?
In UI applications:
- WPF
- WinForms
the continuation often needs to return to the UI thread.
Example:
await LoadDataAsync();
// update UI
textBox.Text = result;
The context is needed.
In server applications:
- ASP.NET Core
there is usually no synchronization context.
Using:
ConfigureAwait(false)
can avoid unnecessary context switching.
Senior Interview Answer
In library code, I often use ConfigureAwait(false) because the library should not depend on a caller's synchronization context.
4. What is a deadlock in asynchronous programming?
Interview Answer
A deadlock occurs when two operations wait for each other indefinitely.
A common async deadlock happens when blocking on an async method.
Example:
var result = GetDataAsync().Result;
or:
GetDataAsync().Wait();
Why is this dangerous?
The async method may need to resume on the captured context, but the thread is blocked waiting for the result.
The continuation cannot execute.
Result:
Thread waiting
|
|
Async operation waiting for thread
Best Practice
Avoid:
.Result
.Wait()
Prefer:
await GetDataAsync();
5. What is thread safety?
Interview Answer
Thread safety means that code behaves correctly when accessed by multiple threads simultaneously.
Example problem:
counter++;
This looks simple, but internally it involves:
- Read value
- Increment value
- Write value
Two threads can interfere.
Example Problem
Initial:
counter = 0
Thread A:
Read 0
Add 1
Thread B:
Read 0
Add 1
Result:
counter = 1
Expected:
counter = 2
Solutions
- lock
- Interlocked
- concurrent collections
- immutable objects
6. What is the lock keyword in C#?
Interview Answer
lock provides mutual exclusion. It ensures only one thread executes a critical section at a time.
Example:
private readonly object sync = new();
public void Increment()
{
lock(sync)
{
counter++;
}
}
How it works
Internally:
Monitor.Enter()
try
{
}
finally
{
Monitor.Exit()
}
When to use lock?
Use when:
- protecting shared state
- multiple threads access the same resource
Avoid locking:
- long-running operations
- network calls
- database calls
Example:
Bad:
lock(sync)
{
await SaveToDatabaseAsync();
}
7. What is Monitor in C#?
Interview Answer
Monitor is the underlying synchronization mechanism used by lock.
Example:
Monitor.Enter(sync);
try
{
counter++;
}
finally
{
Monitor.Exit(sync);
}
Features
Monitor supports:
- locking
- waiting
- signaling
Example:
Monitor.Wait()
Monitor.Pulse()
Difference between lock and Monitor
lock:
- simpler syntax
- automatically releases lock
Monitor:
- more control
- supports advanced synchronization scenarios
8. What is Interlocked in C#?
Interview Answer
Interlocked provides atomic operations for simple shared variables.
Example:
Interlocked.Increment(ref counter);
Instead of:
counter++;
Common Methods
Interlocked.Increment()
Interlocked.Decrement()
Interlocked.Exchange()
Interlocked.CompareExchange()
When to use?
For simple operations:
- counters
- flags
- atomic updates
Example
Without Interlocked:
counter++;
With Interlocked:
Interlocked.Increment(ref counter);
The operation cannot be interrupted.
9. What is SemaphoreSlim?
Interview Answer
SemaphoreSlim limits the number of threads or tasks that can access a resource simultaneously.
Example:
private SemaphoreSlim semaphore =
new SemaphoreSlim(3);
public async Task ProcessAsync()
{
await semaphore.WaitAsync();
try
{
await DoWorkAsync();
}
finally
{
semaphore.Release();
}
}
This allows:
Maximum 3 operations at the same time
Common Uses
- limiting API calls
- controlling database access
- throttling background jobs
Example
A service allows only 10 external API requests simultaneously.
Use:
new SemaphoreSlim(10);
10. What are concurrent collections in .NET?
Interview Answer
Concurrent collections are thread-safe collections designed for multi-threaded applications.
Namespace:
System.Collections.Concurrent
Examples
ConcurrentDictionary
Thread-safe dictionary:
var cache = new ConcurrentDictionary<int,string>();
cache.TryAdd(1,"John");
ConcurrentQueue
Thread-safe queue:
ConcurrentQueue<string> queue;
ConcurrentBag
Thread-safe unordered collection:
ConcurrentBag<int> numbers;
Why not use List<T>?
A normal collection:
List<int>
is not thread-safe.
Multiple threads modifying it can cause:
- exceptions
- corrupted state
- incorrect results
Senior Interview Answer
For multi-threaded applications, I prefer immutable objects or concurrent collections before adding manual locks because they reduce complexity and synchronization issues.
11. What are expression trees in C#?
Interview Answer
An expression tree represents code as a data structure that can be inspected, modified, and translated at runtime.
Unlike a normal delegate, an expression tree does not execute code directly. It describes the structure of the code.
Example:
Normal delegate:
Func<int, bool> condition = x => x > 10;
This creates executable code.
Expression tree:
Expression<Func<int, bool>> condition =
x => x > 10;
This creates a representation of:
Parameter: x
Operation: GreaterThan
Value: 10
Common Uses
Expression trees are heavily used by:
- Entity Framework Core
- LINQ providers
- mocking frameworks
- dynamic query builders
Example:
var users = db.Users
.Where(u => u.Age > 30);
Entity Framework receives the expression tree and converts it into SQL:
SELECT *
FROM Users
WHERE Age > 30
Senior Answer
Expression trees allow frameworks to analyze C# expressions and translate them into another language, such as SQL.
12. What is the difference between Func<T> and Expression<Func<T>>?
Interview Answer
The difference is execution.
Func
Represents executable code.
Example:
Func<User, bool> filter =
u => u.Age > 18;
The code runs inside .NET.
Expression<Func>
Represents code as data.
Example:
Expression<Func<User,bool>> filter =
u => u.Age > 18;
The framework can inspect and translate it.
Example
LINQ to Objects:
users
.Where(u => u.Age > 18);
Uses:
Func<User,bool>
Entity Framework:
db.Users
.Where(u => u.Age > 18);
Uses:
Expression<Func<User,bool>>
Interview Comparison
Func | Expression |
Executes code | Describes code |
Compiled delegate | Expression tree |
LINQ-to-Objects | LINQ-to-SQL |
Cannot translate | Can translate |
13. What is reflection in more detail?
Interview Answer
Reflection allows examining and manipulating assemblies, types, and members during runtime.
Using reflection, you can:
- discover classes
- inspect methods
- read attributes
- create objects dynamically
- call methods dynamically
Example:
Type type = typeof(Customer);
Console.WriteLine(type.Name);
Get methods:
MethodInfo[] methods =
type.GetMethods();
Create object dynamically:
object obj =
Activator.CreateInstance(type);
Invoke method:
method.Invoke(obj, parameters);
Real-world Examples
Dependency Injection
ASP.NET Core scans assemblies:
services.AddTransient<IService, Service>();
The container uses reflection internally.
Serialization
JSON serializers inspect:
public class Customer
{
public string Name {get;set;}
}
and map properties.
Disadvantages
Reflection:
- is slower than direct calls
- can reduce compile-time safety
- increases complexity
14. What is the dynamic keyword in C#?
Interview Answer
dynamic bypasses compile-time type checking and resolves members at runtime.
Example:
dynamic customer = GetCustomer();
Console.WriteLine(customer.Name);
The compiler does not verify that Name exists.
The check happens during execution.
Normal C#
Customer customer;
customer.Name;
The compiler checks:
"Does Customer have Name?"
Dynamic
dynamic customer;
customer.Name;
The runtime checks.
Common Uses
- COM interop
- working with dynamic JSON
- reflection scenarios
- scripting
Disadvantages
You lose:
- IntelliSense
- compile-time safety
- refactoring support
Example:
dynamic value = 10;
value.SomeMethod();
Compiles but fails at runtime.
15. What is ExpandoObject?
Interview Answer
ExpandoObject allows creating objects with dynamic properties at runtime.
Example:
dynamic user = new ExpandoObject();
user.Name = "John";
user.Age = 30;
The object structure is created dynamically.
Example:
Console.WriteLine(user.Name);
Output:
John
Common Uses
- dynamic data models
- JSON manipulation
- prototypes
Difference from normal class
Class:
public class User
{
public string Name {get;set;}
}
Structure is known at compile time.
ExpandoObject:
dynamic user;
Structure can change.
16. What are attributes and why are they useful?
Interview Answer
Attributes add metadata to code elements.
They allow frameworks to understand additional information about classes, methods, and properties.
Example:
[Required]
public string Name {get;set;}
The attribute tells validation frameworks:
"Name cannot be empty."
Common .NET Attributes
MVC/API
[HttpGet]
[Authorize]
Validation
[Required]
[StringLength(50)]
Serialization
[JsonPropertyName("customer_name")]
How frameworks use attributes
Typical process:
- Framework scans assemblies.
- Finds attributes using reflection.
- Applies behavior.
17. How do you create a custom attribute?
Interview Answer
Create a class derived from Attribute.
Example:
public class AuditAttribute : Attribute
{
public string Description {get;}
public AuditAttribute(string description)
{
Description = description;
}
}
Usage:
[Audit("Creates customer")]
public void CreateCustomer()
{
}
Reading it:
var attributes =
method.GetCustomAttributes();
Real Example
You could create:
[Permission("Admin")]
public void DeleteUser()
{
}
and check permissions automatically.
18. What are iterators in C#?
Interview Answer
An iterator allows a method to return elements one at a time instead of creating the entire collection in memory.
The yield keyword is used.
Example:
public IEnumerable<int> GetNumbers()
{
yield return 1;
yield return 2;
yield return 3;
}
Usage:
foreach(var n in GetNumbers())
{
Console.WriteLine(n);
}
Advantage
Instead of:
return new List<int>
{
1,2,3
};
The values are generated as needed.
Benefits
- lower memory usage
- lazy execution
- better performance for large sequences
19. What is yield return?
Interview Answer
yield return creates an iterator that produces values one at a time.
Example:
public IEnumerable<string> ReadLines()
{
foreach(var line in File.ReadLines("file.txt"))
{
yield return line;
}
}
The caller controls iteration:
foreach(var line in ReadLines())
{
}
Important Point
The method does not execute completely at once.
Execution pauses at:
yield return
and resumes on the next iteration.
20. What is Span<T> in C#?
Interview Answer
Span<T> is a high-performance type that allows working with contiguous memory without allocations.
Namespace:
System;
Example:
Span<int> numbers =
stackalloc int[5];
numbers[0] = 10;
Why Span<T> exists
Traditional approach:
int[] array = new int[1000];
creates heap allocations.
Span<T> can work with:
- stack memory
- arrays
- unmanaged memory
without copying data.
Benefits
- high performance
- fewer allocations
- faster processing
Common Uses
- parsing
- networking
- serializers
- game engines
- high-performance APIs
Example
String parsing:
ReadOnlySpan<char> text = "Hello World";
var first =
text.Slice(0,5);
No new string is created.
Senior Interview Summary
For advanced C# questions, remember:
Expression Trees
"They represent code as data and allow frameworks like Entity Framework to translate expressions into SQL."
Reflection
"It provides runtime inspection but should be used carefully because it reduces performance and type safety."
Dynamic
"Useful when the type is unknown at compile time, but sacrifices compiler checks."
Iterators
"yield enables lazy execution and memory-efficient processing."
Span<T>
"A high-performance memory view that avoids unnecessary allocations."
21. What is the difference between Span<T> and Memory<T>?
Interview Answer
Both Span<T> and Memory<T> provide high-performance access to memory without unnecessary allocations, but they have different lifetime capabilities.
Span<T>
Span<T> is a stack-only type.
It cannot:
- be stored in class fields
- cross await boundaries
- be used inside asynchronous methods
Example:
public void Process()
{
Span<int> numbers = stackalloc int[10];
numbers[0] = 100;
}
Memory<T>
Memory<T> is designed for scenarios where memory needs to survive beyond the current method.
Example:
public class DataProcessor
{
private Memory<byte> buffer;
}
It can be:
- stored in objects
- passed between async methods
- used with Tasks
Comparison
Span<T> | Memory<T> |
Stack-only | Heap-friendly |
Synchronous scenarios | Async scenarios |
Faster | Slightly more overhead |
Cannot cross await | Works with await |
Senior Answer
I use Span<T> for high-performance synchronous processing and Memory<T> when the memory needs to live across asynchronous operations.
22. What is stackalloc in C#?
Interview Answer
stackalloc allocates memory on the stack instead of the managed heap.
Example:
Span<int> numbers = stackalloc int[100];
Normal allocation:
int[] numbers = new int[100];
Memory location:
Managed Heap
stackalloc:
Thread Stack
Advantages
- faster allocation
- no Garbage Collector pressure
- automatic cleanup when method exits
Disadvantages
Stack memory is limited.
Bad:
Span<byte> buffer =
stackalloc byte[100000000];
This can cause stack overflow.
Common Usage
High-performance code:
- parsers
- serializers
- networking libraries
23. What is unsafe code in C#?
Interview Answer
Unsafe code allows direct memory manipulation using pointers.
Example:
unsafe
{
int number = 10;
int* pointer = &number;
Console.WriteLine(*pointer);
}
Why use unsafe code?
Used for:
- interoperability with C/C++
- hardware-level programming
- extreme performance optimization
Requirements
Project must enable:
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
Should you use unsafe code?
Usually no.
Modern .NET provides safer alternatives:
- Span<T>
- Memory<T>
- unmanaged APIs
Senior Answer
I avoid unsafe code unless profiling proves that managed code cannot meet performance requirements.
24. What is boxing and unboxing in C#?
Interview Answer
Boxing converts a value type into an object reference.
Unboxing extracts the value type from the object.
Boxing example:
int number = 10;
object obj = number;
The integer is copied to the heap.
int
|
|
object
Unboxing:
int value = (int)obj;
Performance Issue
Boxing causes:
- memory allocation
- copying
- garbage collection pressure
Example
Avoid:
ArrayList list = new();
list.Add(100);
Because every integer is boxed.
Prefer:
List<int> list = new();
list.Add(100);
No boxing.
25. How do you optimize boxing/unboxing?
Interview Answer
Use generics instead of non-generic collections.
Bad:
ArrayList values = new();
values.Add(10);
Good:
List<int> values = new();
values.Add(10);
Use strongly typed APIs:
Bad:
object Process(object value)
{
}
Better:
T Process<T>(T value)
{
}
Senior Answer
Boxing is often hidden in code, so I use profiling tools to identify allocations before optimizing.
26. What is object pooling?
Interview Answer
Object pooling is a technique where objects are reused instead of constantly created and destroyed.
Instead of:
Create object
Use object
Destroy object
Create object again
Use:
Get object from pool
Use object
Return object to pool
Example
ASP.NET Core provides:
Microsoft.Extensions.ObjectPool
Example:
var pool =
new DefaultObjectPool<MyObject>(
new MyObjectPolicy());
Benefits
- fewer allocations
- less GC pressure
- improved performance
Common Uses
- database connections
- HTTP handlers
- StringBuilder reuse
- game objects
- high-frequency processing
27. What are caching strategies in .NET?
Interview Answer
Caching stores frequently used data to avoid expensive operations.
Common strategies:
1. In-memory cache
Data stored inside application memory.
Example:
IMemoryCache cache;
Good for:
- single-server applications
2. Distributed cache
Data stored outside application.
Examples:
- Redis
- SQL Server cache
Good for:
- cloud applications
- multiple servers
3. Cache-aside pattern
Most common approach.
Flow:
Request
|
Check Cache
|
Found?
|
Return Data
Not Found
|
Load Database
|
Store Cache
|
Return Data
Senior Answer
I choose cache strategy based on consistency requirements, expiration policy, and whether the application is distributed.
28. What are immutable collections in .NET?
Interview Answer
Immutable collections cannot be modified after creation.
Namespace:
System.Collections.Immutable
Examples:
ImmutableList<int> numbers =
ImmutableList.Create(1,2,3);
Adding an item:
var updated =
numbers.Add(4);
The original collection remains unchanged.
Benefits
- thread safety
- predictable behavior
- safer concurrent programming
Examples
- ImmutableList<T>
- ImmutableDictionary<TKey,TValue>
- ImmutableHashSet<T>
29. What is the difference between class and struct in C#?
Interview Answer
The main difference is that classes are reference types and structs are value types.
Class
Stored as reference:
class Customer
{
public string Name;
}
Example:
Customer c1 = new();
Customer c2 = c1;
Both reference the same object.
Struct
Stored as value:
struct Point
{
public int X;
public int Y;
}
Example:
Point p1 = new();
Point p2 = p1;
A copy is created.
Comparison
Class | Struct |
Reference type | Value type |
Heap allocation | Usually stack/inline |
Supports inheritance | No class inheritance |
Larger objects | Small data objects |
When to use struct?
Good for:
- small immutable values
- coordinates
- dates
- measurements
Examples:
DateTime
Guid
decimal
30. What are record types in C# and how are they different from classes?
Interview Answer
Records are reference types designed mainly for immutable data models and value-based equality.
Example:
public record Customer(
string Name,
int Age);
Class comparison
Class:
var c1 = new Customer("John",30);
var c2 = new Customer("John",30);
c1 == c2;
Usually:
False
because references differ.
Record:
var r1 = new Customer("John",30);
var r2 = new Customer("John",30);
r1 == r2;
Result:
True
because values are compared.
Records provide:
- value equality
- immutable properties
- concise syntax
- with-expressions
Example:
var updated =
customer with { Age = 31 };
When to use records?
Good for:
- DTOs
- API models
- messages
- immutable data
Avoid for:
- entities with identity
- objects with complex lifecycle
Senior Interview Summary
Important concepts:
Span<T>
"A high-performance memory view that avoids allocations."
Boxing
"Converting value types to objects creates allocations and should be minimized."
Object Pooling
"Reuse expensive objects to reduce GC pressure."
Struct
"Use for small value types where copying is cheaper than heap allocation."
Records
"Use for immutable data transfer models with value-based equality."
31. What is the difference between Select and SelectMany in LINQ?
Interview Answer
Both are projection operators, but they work differently.
Select
Select transforms each element into another form.
Example:
var names = customers
.Select(c => c.Name);
Input:
Customer[]
|
|
string[]
Example:
var numbers = new[] {1,2,3};
var result = numbers.Select(x => x * 2);
Result:
2,4,6
SelectMany
SelectMany flattens nested collections into a single collection.
Example:
class Customer
{
public string Name {get;set;}
public List<Order> Orders {get;set;}
}
Without SelectMany:
var orders =
customers.Select(c => c.Orders);
Result:
List<Order>
List<Order>
List<Order>
Nested collections.
With SelectMany:
var orders =
customers.SelectMany(c => c.Orders);
Result:
Order
Order
Order
Order
Senior Answer
I use Select for one-to-one transformations and SelectMany when I need to flatten nested collections.
32. How does GroupBy work in LINQ?
Interview Answer
GroupBy groups elements based on a key.
Example:
var employeesByDepartment =
employees.GroupBy(e => e.Department);
Result:
IT
├── John
├── Mary
HR
├── Alex
├── Peter
Example:
foreach(var group in employeesByDepartment)
{
Console.WriteLine(group.Key);
foreach(var employee in group)
{
Console.WriteLine(employee.Name);
}
}
SQL Equivalent
LINQ:
employees.GroupBy(e => e.Department)
SQL:
SELECT Department, COUNT(*)
FROM Employees
GROUP BY Department
Performance Consideration
GroupBy usually loads data into memory.
For large database tables:
Prefer:
IQueryable
so the grouping can happen in SQL.
33. What are Join operations in LINQ?
Interview Answer
LINQ joins combine data from two collections based on a matching key.
Example:
var result =
customers.Join(
orders,
c => c.Id,
o => o.CustomerId,
(customer, order) =>
new
{
customer.Name,
order.Amount
});
Equivalent SQL:
SELECT
Customers.Name,
Orders.Amount
FROM Customers
JOIN Orders
ON Customers.Id = Orders.CustomerId
Types of LINQ joins
Inner Join
Returns matching records only.
Example:
Customers
+
Orders
Only customers with orders.
Left Join
Returns all records from the left side.
Example:
All customers, even without orders.
LINQ uses:
DefaultIfEmpty()
for left joins.
34. What is Aggregate in LINQ?
Interview Answer
Aggregate applies a function repeatedly to combine values into a single result.
Example:
var numbers = new[] {1,2,3,4};
var sum =
numbers.Aggregate(
0,
(total, number) => total + number);
Result:
10
Execution:
0 + 1 = 1
1 + 2 = 3
3 + 3 = 6
6 + 4 = 10
Common Uses
- calculations
- string building
- custom reductions
Example:
var sentence =
words.Aggregate(
"",
(a,b) => a + " " + b);
Difference from Sum()
Instead of:
numbers.Sum();
Use Aggregate when the operation is custom.
35. What is deferred execution in LINQ?
Interview Answer
Deferred execution means a LINQ query is not executed when it is created.
It executes when the results are requested.
Example:
var query =
customers.Where(c => c.Active);
Nothing has happened yet.
Execution occurs:
var list = query.ToList();
Benefits
- avoids unnecessary work
- allows query composition
- improves efficiency
Example:
var query =
customers
.Where(c => c.Active)
.OrderBy(c => c.Name);
The entire query executes only at:
.ToList()
36. What is immediate execution in LINQ?
Interview Answer
Immediate execution happens when a LINQ method forces the query to run immediately.
Examples:
.ToList()
.ToArray()
.Count()
.First()
.Single()
Example:
var users =
db.Users
.Where(u => u.Active)
.ToList();
The SQL executes immediately.
Important Interview Point
Calling:
Count()
executes the query.
Calling:
Where()
does not.
37. What is the difference between IEnumerable and IQueryable internally?
Interview Answer
The main difference is how LINQ expressions are executed.
IEnumerable
Works with:
Objects in memory
Example:
List<Customer> customers;
customers
.Where(c => c.Active);
Execution:
Database
|
Load all data
|
Memory filtering
IQueryable
Builds an expression tree.
Example:
db.Customers
.Where(c => c.Active);
Execution:
LINQ Expression
|
Entity Framework
|
SQL
|
Database
Senior Answer
IQueryable allows the query provider to translate expressions into another language, such as SQL, while IEnumerable executes using CLR objects.
38. What are LINQ expression trees used for?
Interview Answer
Expression trees allow LINQ providers to analyze queries.
Example:
Expression<Func<Customer,bool>>
represents:
customer => customer.Active
as a structure:
Lambda Expression
|
+-- Parameter: customer
|
+-- Property: Active
|
+-- Operator: Equal
Entity Framework converts it:
C#:
.Where(c => c.Active)
SQL:
WHERE Active = 1
39. How can you improve LINQ performance?
Interview Answer
Several techniques improve LINQ performance:
1. Avoid unnecessary ToList()
Bad:
var list =
customers
.Where(c=>c.Active)
.ToList()
.OrderBy(c=>c.Name);
The query executes too early.
Better:
var result =
customers
.Where(c=>c.Active)
.OrderBy(c=>c.Name)
.ToList();
2. Select only required fields
Bad:
var users =
db.Users.ToList();
Loads everything.
Better:
var users =
db.Users
.Select(x => new
{
x.Id,
x.Name
});
3. Avoid multiple enumeration
Bad:
var count = query.Count();
var first = query.First();
The query executes twice.
Better:
var list = query.ToList();
var count = list.Count;
var first = list.First();
40. What are common LINQ mistakes?
Interview Answer
Mistake 1: Executing queries too early
Bad:
var users =
db.Users
.ToList()
.Where(u => u.Active);
The database returns all users first.
Better:
var users =
db.Users
.Where(u => u.Active)
.ToList();
Mistake 2: Loading unnecessary data
Bad:
var customers =
db.Customers.ToList();
Better:
var customers =
db.Customers
.Select(c => c.Name)
.ToList();
Mistake 3: N+1 queries
Example:
foreach(var customer in customers)
{
customer.Orders.Count();
}
May generate many database calls.
Better:
Use:
- Include()
- projection
- joins
Senior Interview Summary
Important LINQ concepts:
Select
"Transforms each item."
SelectMany
"Flattens nested collections."
IQueryable
"Allows query translation, usually into SQL."
Deferred Execution
"Queries execute only when results are requested."
Performance
"Filter and project data at the database level whenever possible."
41. How does Dependency Injection work internally in ASP.NET Core?
Interview Answer
Dependency Injection (DI) is a design pattern where objects receive their dependencies from an external container instead of creating them directly.
Without DI:
public class OrderService
{
private readonly EmailService emailService;
public OrderService()
{
emailService = new EmailService();
}
}
Problems:
- tight coupling
- difficult testing
- difficult replacement
With DI:
public class OrderService
{
private readonly IEmailService emailService;
public OrderService(
IEmailService emailService)
{
this.emailService = emailService;
}
}
Registration:
services.AddScoped<IEmailService, EmailService>();
The framework creates and injects the dependency.
Internally
ASP.NET Core uses:
Service Collection
|
|
Service Provider
|
|
Object Creation
|
|
Constructor Injection
The container:
- Finds the requested service.
- Determines its dependencies.
- Creates required objects.
- Controls their lifetime.
Senior Answer
Dependency Injection reduces coupling and improves testability. ASP.NET Core has a built-in DI container that manages object creation and lifetimes.
42. What is IServiceCollection and IServiceProvider?
Interview Answer
They are the two main parts of ASP.NET Core Dependency Injection.
IServiceCollection
Used during application startup to register services.
Example:
builder.Services.AddScoped<IUserService, UserService>();
It stores service registrations.
IServiceProvider
Used at runtime to resolve services.
Example:
var service =
provider.GetService<IUserService>();
It creates objects based on registrations.
Flow
IServiceCollection
(Register services)
↓
IServiceProvider
(Create objects)
↓
Application
43. What are the DI service lifetimes in ASP.NET Core?
Interview Answer
ASP.NET Core provides three lifetimes.
Transient
A new instance every time requested.
services.AddTransient<IEmailService, EmailService>();
Example:
Request A
|
EmailService #1
Request A
|
EmailService #2
Good for:
- lightweight services
- stateless operations
Scoped
One instance per request.
services.AddScoped<IOrderService, OrderService>();
Example:
HTTP Request
|
OrderService
|
Database Context
Common for:
- business services
- Entity Framework DbContext
Singleton
One instance for application lifetime.
services.AddSingleton<ICache, Cache>();
Good for:
- configuration
- caching
- shared services
Interview Tip
Remember:
Transient = Every time
Scoped = Every request
Singleton = Application lifetime
44. What is middleware in ASP.NET Core?
Interview Answer
Middleware is a component that handles HTTP requests and responses in the ASP.NET Core pipeline.
Example:
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
Pipeline Example
HTTP Request
|
v
Logging Middleware
|
v
Authentication Middleware
|
v
Authorization Middleware
|
v
Controller
|
v
HTTP Response
Custom Middleware Example
public class LoggingMiddleware
{
private readonly RequestDelegate next;
public LoggingMiddleware(
RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context)
{
Console.WriteLine(
context.Request.Path);
await next(context);
}
}
Registration:
app.UseMiddleware<LoggingMiddleware>();
45. What is the difference between middleware and filters?
Interview Answer
Both can intercept requests, but they work at different levels.
Middleware
Works at HTTP pipeline level.
Examples:
- authentication
- logging
- exception handling
- CORS
Runs before MVC.
Filters
Work inside MVC pipeline.
Examples:
- authorization filters
- action filters
- exception filters
Example:
public class AuditFilter : IActionFilter
{
}
Comparison
Middleware | Filter |
HTTP pipeline | MVC pipeline |
Applies globally | Controller/action level |
Framework independent | MVC specific |
Senior Answer
I use middleware for cross-cutting concerns that apply to the whole application and filters when behavior is specific to MVC actions.
46. What are Background Services in ASP.NET Core?
Interview Answer
Background services allow running long-running tasks outside the normal HTTP request pipeline.
They are implemented using:
BackgroundService
Example:
public class EmailWorker
: BackgroundService
{
protected override async Task ExecuteAsync(
CancellationToken stoppingToken)
{
while(!stoppingToken.IsCancellationRequested)
{
await SendEmails();
await Task.Delay(
5000,
stoppingToken);
}
}
}
Registration:
services.AddHostedService<EmailWorker>();
Common Uses
- queue processing
- scheduled jobs
- notifications
- data synchronization
- monitoring tasks
47. What is the difference between IHostedService and BackgroundService?
Interview Answer
BackgroundService is an abstract implementation of IHostedService.
IHostedService
You implement:
StartAsync()
StopAsync()
Example:
public class Worker : IHostedService
{
}
BackgroundService
Provides a simpler model:
protected abstract Task ExecuteAsync();
Example:
public class Worker
: BackgroundService
{
}
Senior Answer
I usually use BackgroundService because it provides a cleaner implementation for continuous background processing.
48. How does configuration work in ASP.NET Core?
Interview Answer
ASP.NET Core uses a configuration system that combines values from multiple sources.
Common sources:
- appsettings.json
- appsettings.Environment.json
- environment variables
- command-line arguments
- Azure Key Vault
- user secrets
Example:
appsettings.json:
{
"Database": {
"ConnectionString": "Server=myserver"
}
}
Read:
var value =
configuration["Database:ConnectionString"];
Priority
Later providers override earlier ones.
Example:
appsettings.json
↓
Environment Variables
↓
Command Line
49. How does logging work in ASP.NET Core?
Interview Answer
ASP.NET Core provides built-in logging through:
ILogger<T>
Example:
public class OrderService
{
private readonly ILogger<OrderService> logger;
public OrderService(
ILogger<OrderService> logger)
{
this.logger = logger;
}
public void Process()
{
logger.LogInformation(
"Order processed");
}
}
Log Levels
From lowest to highest:
Trace
Debug
Information
Warning
Error
Critical
Logging Providers
Examples:
- Console
- Debug
- EventSource
- Serilog
- Application Insights
Senior Answer
I use structured logging instead of plain text because it allows better searching and analysis in production environments.
Example:
logger.LogInformation(
"Order {OrderId} created",
orderId);
50. What are Health Checks in ASP.NET Core?
Interview Answer
Health checks provide endpoints that report whether an application and its dependencies are healthy.
Example:
Registration:
services.AddHealthChecks();
Endpoint:
app.MapHealthChecks("/health");
A monitoring system can call:
GET /health
Response:
{
"status":"Healthy"
}
What can health checks test?
Examples:
- database connection
- Redis availability
- external APIs
- message queues
Example:
services
.AddHealthChecks()
.AddSqlServer(connectionString);
Common Usage
Used by:
- Kubernetes
- Azure App Service
- AWS ECS
- load balancers
Senior Interview Summary
Important ASP.NET Core concepts:
Dependency Injection
"The container manages object creation and lifetime."
Middleware
"Middleware forms the HTTP request processing pipeline."
BackgroundService
"Used for long-running tasks outside HTTP requests."
Configuration
"Multiple providers are combined with later providers overriding earlier values."
Logging
"Use structured logging for production diagnostics."
Health Checks
"Used by infrastructure to determine application availability."
51. What are Minimal APIs in ASP.NET Core?
Interview Answer
Minimal APIs provide a lightweight way to build HTTP APIs without the traditional Controller-based approach.
Introduced in .NET 6, they reduce boilerplate code.
Traditional Controller:
[ApiController]
[Route("api/users")]
public class UsersController : ControllerBase
{
[HttpGet]
public IEnumerable<User> Get()
{
return users;
}
}
Minimal API:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/users", () =>
{
return users;
});
app.Run();
Advantages
- less code
- faster startup
- good for small services
- excellent for microservices
When to use?
Good for:
- lightweight APIs
- microservices
- serverless endpoints
Use Controllers for:
- large enterprise applications
- complex API organization
Senior Answer
Minimal APIs are useful when simplicity and performance are priorities, while Controllers provide better structure for large enterprise applications.
52. What is endpoint routing in ASP.NET Core?
Interview Answer
Endpoint routing maps incoming HTTP requests to application endpoints.
Example:
app.MapGet("/customers/{id}",
(int id) =>
{
return GetCustomer(id);
});
Request:
GET /customers/10
is mapped to:
Handler(id = 10)
Routing Pipeline
HTTP Request
|
v
Routing Middleware
|
v
Endpoint Selection
|
v
Controller / Minimal API
|
v
Response
Benefits
- centralized routing
- supports authorization metadata
- supports middleware integration
53. What is the difference between authentication and authorization?
Interview Answer
Authentication answers:
"Who are you?"
Authorization answers:
"What are you allowed to do?"
Authentication Example
User logs in:
Username + Password
|
Identity verified
|
JWT Token created
Authorization Example
User has:
Role = Manager
Can access:
/reports
but not:
/admin/settings
ASP.NET Core Example
Authentication:
app.UseAuthentication();
Authorization:
app.UseAuthorization();
Senior Answer
Authentication establishes identity, while authorization determines permissions based on roles, claims, or policies.
54. What are claims in ASP.NET Core?
Interview Answer
Claims are pieces of information about a user.
Examples:
UserId = 123
Email = john@test.com
Role = Admin
Department = Finance
JWT example:
{
"sub":"123",
"name":"John",
"role":"Admin"
}
Access claims:
var userId =
User.FindFirst("sub")?.Value;
Why use claims?
Claims support:
- role-based security
- permission systems
- identity management
55. What are authorization policies in ASP.NET Core?
Interview Answer
Policies provide flexible authorization rules beyond simple roles.
Example:
Create policy:
builder.Services
.AddAuthorization(options =>
{
options.AddPolicy(
"SeniorEmployee",
policy =>
{
policy.RequireClaim(
"Level",
"Senior");
});
});
Use:
[Authorize(
Policy="SeniorEmployee")]
public IActionResult Reports()
{
return View();
}
Advantages
Policies allow rules based on:
- claims
- roles
- custom requirements
- business logic
Senior Answer
Policies are preferable to hardcoded role checks because they separate authorization rules from application code.
56. How do JWT tokens work?
Interview Answer
JWT (JSON Web Token) is a compact token used for authentication between clients and servers.
A JWT contains three parts:
Header.Payload.Signature
Example:
xxxxx.yyyyy.zzzzz
Authentication Flow
Client
|
| username/password
v
Authentication Server
|
| JWT Token
v
Client
|
| Authorization: Bearer token
v
API
JWT Structure
Header:
{
"alg":"HS256"
}
Payload:
{
"userId":123,
"role":"Admin"
}
Signature:
Used to verify the token was not modified.
Advantages
- stateless
- scalable
- works well with distributed systems
Disadvantages
- cannot easily revoke tokens
- token size larger than cookies
57. How do you implement global exception handling in ASP.NET Core?
Interview Answer
Global exception handling centralizes error processing.
Instead of:
try
{
}
catch(Exception ex)
{
}
everywhere, use middleware.
Example:
app.UseExceptionHandler("/error");
Custom middleware:
public class ExceptionMiddleware
{
private readonly RequestDelegate next;
public async Task Invoke(HttpContext context)
{
try
{
await next(context);
}
catch(Exception ex)
{
context.Response.StatusCode = 500;
}
}
}
Benefits
- consistent responses
- centralized logging
- hides internal details
Example response:
{
"message":"An unexpected error occurred"
}
58. What is the Result Pattern?
Interview Answer
The Result Pattern represents success or failure without using exceptions for normal business flow.
Instead of:
throw new Exception(
"Insufficient balance");
Use:
return Result.Fail(
"Insufficient balance");
Example:
public class Result<T>
{
public bool Success {get;}
public string Error {get;}
public T Value {get;}
}
Usage:
var result =
service.CreateOrder();
if(!result.Success)
{
return BadRequest(result.Error);
}
Benefits
- clearer business logic
- fewer exceptions
- easier testing
Common Use
Used in:
- Clean Architecture
- CQRS
- enterprise applications
59. What is Fluent API in Entity Framework Core?
Interview Answer
Fluent API configures database mappings using C# code instead of attributes.
Example:
protected override void OnModelCreating(
ModelBuilder builder)
{
builder.Entity<Customer>()
.HasKey(x => x.Id);
}
Configure relationships:
Example:
builder.Entity<Order>()
.HasOne(o => o.Customer)
.WithMany(c => c.Orders)
.HasForeignKey(o => o.CustomerId);
Fluent API vs Data Annotations
Fluent API | Attributes |
More powerful | Simpler |
Central configuration | Mixed with model |
Better for complex mappings | Good for simple cases |
Senior Answer
For enterprise systems I usually prefer Fluent API because it keeps domain models clean.
60. What are EF Core performance optimization techniques?
Interview Answer
Important EF Core optimization techniques:
1. Select only required columns
Bad:
var users =
db.Users.ToList();
Loads everything.
Better:
var users =
db.Users
.Select(x => new
{
x.Id,
x.Name
})
.ToList();
2. Use AsNoTracking for read-only queries
Default:
db.Users.ToList();
EF tracks changes.
For reports:
db.Users
.AsNoTracking()
.ToList();
Less memory usage.
3. Avoid N+1 queries
Bad:
foreach(var customer in customers)
{
customer.Orders.Count();
}
Can create many SQL calls.
Better:
db.Customers
.Include(c => c.Orders);
4. Use pagination
Bad:
db.Products.ToList();
Better:
db.Products
.Skip(100)
.Take(50);
5. Use indexes
Example:
CREATE INDEX IX_User_Email
ON Users(Email)
Senior Answer
EF Core performance depends on controlling generated SQL, minimizing data transfer, using proper indexes, and avoiding unnecessary tracking.
Chapter 3 — Advanced C# Completed ✅
Total Questions Completed: 60
You should now be comfortable answering:
✅ Async/await
✅ Multithreading
✅ Locks and synchronization
✅ Reflection
✅ Expression trees
✅ LINQ internals
✅ Memory optimization
✅ Dependency Injection
✅ Middleware
✅ Authentication
✅ JWT
✅ EF Core optimization