Advanced C# Interview Questions
Every question has a short model answer and a link to the lesson example that shows it in code. Levels: F = Fresher (0-2 yrs), M = Mid (3-5 yrs), S = Senior (6-9 yrs), A = Architect / Lead (10+ yrs).
Collections
FWhat is the difference between an array and a List<T>?concept
An array has a fixed size set when it is created. A List<T> grows and shrinks with Add and
Remove, using an array inside that it replaces with a bigger one when full. Use arrays for fixed
data and lists for data that changes.
FWhen would you use a Dictionary<TKey, TValue>?concept
When you look values up by a unique key, such as students by admission number. Lookup time stays about the same however many items it holds, unlike searching a list.
FWhat is the difference between a Queue and a Stack?concept
A Queue<T> is first in, first out: Enqueue adds at the back, Dequeue takes from the front,
like a fee counter line. A Stack<T> is last in, first out: Push and Pop work on the top,
like undo.
MWhy is looking up by key in a Dictionary faster than searching a List?concept
A list search checks items one by one, so on average half the list per search. A dictionary hashes the key to jump almost directly to its bucket, taking about constant time. In the SMS, finding 1,006 students took about 24 ms with a list and 0.1 ms with a dictionary.
MWhat is the difference between dict[key] and dict.TryGetValue(key, out value)?coding
The indexer throws KeyNotFoundException when the key is missing. TryGetValue returns false
instead and gives the value through out when found. Use TryGetValue whenever the key may be absent.
MWhat does 'Collection was modified; enumeration operation may not execute' mean?concept
The list was changed, for example by Remove, while a foreach was looping over it. Collect the
items to change and apply the changes after the loop, or loop backwards with a for loop.
SAn end-of-term report takes minutes. It loops over students and, for each, searches a list of all marks. How do you fix it?scenario
The nested search does students times marks comparisons. Group the marks into a Dictionary
keyed by student once, then look each student up in constant time. The work drops from
millions of comparisons to one pass plus one lookup per student.
Identify the nested loop as the cause, explain the complexity in plain terms, and show the dictionary fix with a measurement before and after.
SHow should a class expose a collection it owns?design
Keep the real list private and expose it as IReadOnlyList<T> or IReadOnlyCollection<T>, so
callers can read but not add or remove. Changes go through the class's own methods, which keep
its rules. Initialise collections to empty, never null.
Connect it to encapsulation, show the property pattern, and mention that returning the mutable list lets callers bypass validation.
AHow do you choose the right collection for a feature?design
Start from how the data is used: in order and by position (List), by key (Dictionary), uniqueness checks (HashSet), arrival order (Queue), last-first (Stack), and whether many threads share it (concurrent collections). Measure with realistic data volumes before optimizing further.
Give a decision approach based on access patterns and scale, with SMS examples, and mention thread safety and memory as further factors.
Generics
FWhat are generics in C#?concept
Classes, records, interfaces, and methods written with a type parameter, such as T, that the
caller fills in. List<Student> and PagedResult<StudentDto> reuse one definition for many types,
with full compile-time type checking.
FWhat is a generic method?concept
A method with its own type parameter, written after its name, such as
ToPage<T>(List<T> all, int page, int pageSize). The compiler usually infers T from the
arguments, so callers rarely write it.
FWhy are generic collections better than ArrayList?concept
ArrayList holds object, so wrong types are accepted and fail later with
InvalidCastException, and value types are boxed. List<decimal> rejects a string at compile time
and stores decimals directly, which is safer and faster.
MWhat are generic constraints? Give examples.concept
Rules on what a type parameter may be, written with where: where T : ISoftDeletable,
where T : class, where T : struct, where T : new(). They let the generic code use the
promised members, and the compiler rejects types that do not qualify (CS0311).
MWhat is boxing, and how do generics avoid it?concept
Boxing wraps a value type, such as a decimal, in an object on the heap so it can be stored as
object; unboxing casts it back. It costs memory and time. Generic collections store the value
type directly, so no boxing happens.
MWhy can't a List<Student> be assigned to a List<Person>, while IEnumerable<Person> works?concept
Through a List<Person>, code could add a Teacher into a list of students, so C# forbids it
(CS0029). IEnumerable<T> only reads, so treating students as persons is safe; this is
covariance, marked by out T on the interface.
SFour teams each built their own paging response for the API, and the mobile app struggles. What do you do?scenario
Define one generic PagedResult<T> in the shared library with agreed names, 1-based pages, and
a maximum page size, and migrate endpoints to it gradually, keeping old shapes until clients
move. Clients then need one paging routine.
Cover the shared contract, the rules it enforces (page size limits), and a safe migration plan with versioning or a transition period for existing clients.
SWhat are the pros and cons of a generic repository, IRepository<T>?design
Pros: less repetitive code and a uniform interface. Cons: every entity gets the same methods, including Delete where rules forbid it; special queries are awkward; and it often duplicates what an ORM already provides. Specific repositories, possibly sharing a small generic base, are a common choice.
Present both sides fairly, tie the decision to business rules (forbidden deletes) and query needs, and mention that EF Core's DbSet already acts as a generic repository.
AHow would you design shared generic building blocks for a large API without over-generalizing?design
Generalize proven, repeated shapes, such as paging, result wrappers, and soft-delete filters, with minimal constraints, in a shared library. Keep domain logic specific. Make something generic only when a second real use appears, and document the conventions so teams use them consistently.
Show judgment: name good candidates and bad ones (generic services hiding business rules), discuss constraints and naming, and the cost of changing widely used generic types.
IEnumerable and IQueryable
FWhat is IEnumerable<T>?concept
The interface for anything you can walk through one item at a time. It provides an enumerator,
which foreach uses. Arrays, lists, dictionaries, and LINQ queries all implement it.
See the example · Lesson 49: IEnumerable vs IQueryable · Permalink
FWhat does yield return do?concept
It hands back one item from a method that returns IEnumerable<T>, then pauses the method until
the caller asks for the next item. Data is streamed: reading the marks file with Take(3) read
only 71 of 12,012 lines.
See the example · Lesson 49: IEnumerable vs IQueryable · Permalink
FWhat is deferred execution in LINQ?concept
Building a query with methods like Where does not run it; it creates a plan. The plan runs only
when results are requested, by foreach, Count(), First(), ToList(), and similar calls.
See the example · Lesson 49: IEnumerable vs IQueryable · Permalink
MWhat is the difference between IEnumerable<T> and IQueryable<T>?concept
An IEnumerable query holds compiled code and runs in your application's memory. An
IQueryable query holds an expression tree that a provider translates, for example EF Core
into SQL, so filtering happens in the database before rows are sent.
See the example · Lesson 49: IEnumerable vs IQueryable · Permalink
MWhat is multiple enumeration, and how do you avoid it?concept
Enumerating the same deferred query more than once repeats all its work each time; two Count()
calls read the marks file twice. If the results are needed several times, call ToList() once and
reuse the list.
See the example · Lesson 49: IEnumerable vs IQueryable · Permalink
MWhy prefer Any() over Count() > 0?coding
Any() stops at the first matching item; Count() must examine every item. Against a database,
Any() becomes an EXISTS check while Count() counts every matching row.
See the example · Lesson 49: IEnumerable vs IQueryable · Permalink
SA dashboard calls context.AttendanceRecords.ToList() and then filters today's records in C#. It is slow and uses a lot of memory. Why, and what is the fix?scenario
ToList() runs the query immediately, so every attendance row is loaded into memory before
filtering. Apply Where while the query is still IQueryable, then ToList(), so SQL Server
returns only today's rows.
Explain where the query runs before and after the fix, quantify the waste (all rows versus a few hundred), and mention checking the generated SQL or logs to confirm.
See the example · Lesson 49: IEnumerable vs IQueryable · Permalink
SShould a repository return IQueryable<T>?design
Usually not. Returning IQueryable lets callers compose any query against the database, spreading
data access logic and making performance unpredictable. Return materialized results such as
IReadOnlyList<T>, and add specific methods for the queries you need.
Present the trade-off: flexibility versus control and testability. Mention cases where exposing IQueryable is deliberate, such as OData or internal query builders.
See the example · Lesson 49: IEnumerable vs IQueryable · Permalink
AHow would you process millions of rows in .NET without running out of memory?design
Stream instead of materializing: read rows one at a time with an iterator, a data reader, or
IAsyncEnumerable<T>, process each, and keep only aggregates. Filter and aggregate in the database
where possible, and batch writes.
Combine database-side work, streaming in the application, batching, and measuring memory. Mention that ToList on huge results is the usual cause of memory spikes.
See the example · Lesson 49: IEnumerable vs IQueryable · Permalink
LINQ
FWhat is LINQ?concept
Language Integrated Query: a set of C# methods and syntax for querying any collection, such as
Where, Select, OrderBy, and GroupBy. The same queries work on lists, files, and, through EF
Core, databases.
FWhat is the difference between Where and Select?concept
Where filters: it keeps items that match a condition. Select projects: it turns each item into
a new shape, such as a name and a mark. Filter first, then shape.
FWhat is the difference between First, FirstOrDefault, and Single?concept
First returns the first match and throws if there is none. FirstOrDefault returns default
(null for classes) instead of throwing. Single expects exactly one match and throws for none or
for more than one.
MHow does LINQ's Average treat null values?concept
For nullable values, Average, Max, and Min skip nulls, like SQL's AVG. The Class 10
Mathematics average of 60.23 ignored 20 absent students, matching SQL Server exactly.
MHow does GroupBy work in LINQ?coding
GroupBy(m => m.Subject) returns groups; each has a Key (the subject) and is itself the sequence
of items with that key, so g.Average(...) and g.Count() work per group, like SQL's GROUP BY.
MWhat is the difference between Select and SelectMany?concept
Select returns one result per item, so a list of sections with enrollments becomes a list of
lists. SelectMany flattens those inner lists into one sequence: 22 sections become 1,006
enrollments.
SA results screen shows a different rank-1 student on every refresh. What is wrong?scenario
Several students share the top mark and the sort has no tie-breaker, so their order is not fixed.
Add ThenBy on a stable key, and agree a ranking rule with the school, such as equal marks
sharing a rank (DENSE_RANK).
Explain non-deterministic ordering, the technical fix, and the business question behind it. Mention the same issue in SQL ORDER BY without a unique key.
SQuery syntax or method syntax: which do you use?concept
Both compile to the same calls. Method syntax is shorter for simple chains and offers every operator; query syntax reads more easily for joins and multiple sources. Many teams default to method syntax and use query syntax for complex joins.
Show you can read and write both, then state a consistent team preference and its reason.
AWhen does LINQ hurt performance, and how do you prevent it in a team?design
Through searches inside loops instead of dictionaries, repeated enumeration of deferred queries, materializing database queries too early, and sorting before filtering. Prevent it with code review rules, analyzers for multiple enumeration, logging of generated SQL, and measuring hot paths.
Give concrete anti-patterns with fixes, then the team-level practices. Emphasize measuring before replacing readable LINQ with hand-written loops.
Delegates and events
FWhat is a delegate?concept
A type-safe reference to a method, stored in a variable and passed around like a value. Func,
Action, and EventHandler<T> are built-in delegate types; LINQ's Where takes a delegate.
See the example · Lesson 51: Delegates and events · Permalink
FWhat is the difference between Func and Action?concept
Func returns a value; its last type parameter is the return type, as in Func<decimal, string>.
Action returns nothing, as in Action<string>.
See the example · Lesson 51: Delegates and events · Permalink
FWhat is a lambda expression?concept
An inline, unnamed method, such as m => m.MarksObtained is null. It is converted into a delegate
(or an expression tree for IQueryable), with parameter types inferred from where it is used.
See the example · Lesson 51: Delegates and events · Permalink
MWhat is an event, and how does it differ from a public delegate field?concept
An event is a delegate wrapped so that outside code can only subscribe (+=) and unsubscribe
(-=); only the owning class can raise it. A public delegate field could be overwritten or invoked
by anyone, faking notifications (CS0079 prevents this for events).
See the example · Lesson 51: Delegates and events · Permalink
MWhat is a closure?concept
A lambda that captures variables from its surrounding scope. It captures the variable itself, not a copy, so changes are shared and the captured objects stay alive as long as the lambda does.
See the example · Lesson 51: Delegates and events · Permalink
MWhy raise an event with Event?.Invoke(...), and why can't you unsubscribe an inline lambda?coding
With no subscribers the event is null, so ?. avoids a NullReferenceException. Each inline lambda
creates a new delegate, so -= with another identical-looking lambda removes nothing; keep a
reference or use a named method.
See the example · Lesson 51: Delegates and events · Permalink
SRecording a payment calls six features directly, and a bug in any one breaks payments. How would you redesign it?scenario
Have the payment raise one "payment recorded" event, or publish a message, after the payment is saved, and let each feature subscribe independently. Failures in optional reactions should not undo or block the payment; isolate them and log errors.
Connect to Single Responsibility and Open/Closed, discuss error isolation, and mention that across services this becomes messaging with background processing.
See the example · Lesson 51: Delegates and events · Permalink
SWhen would you use an event, an interface, or a Func parameter?design
An event for optional listeners that come and go; an interface for a required collaborator with
several methods, injected through the constructor; a Func parameter for a single rule or formula
chosen by the caller.
Give one SMS example for each and the trade-offs: discoverability, testability, and how failures propagate.
See the example · Lesson 51: Delegates and events · Permalink
AHow do in-process events relate to messaging in a distributed system?design
Both announce that something happened and let others react. In-process events run synchronously in the same program and are lost if it crashes. Messaging (queues, an outbox) is durable, crosses services, retries on failure, and runs asynchronously, at the cost of eventual consistency.
Compare reliability, coupling, and timing, then explain when to promote an event to a message, for example a payment notification that must not be lost.
See the example · Lesson 51: Delegates and events · Permalink
Modern C# features
FWhat is a collection expression?concept
C# 12 syntax for creating collections with square brackets: string[] subjects = ["English", "Science"];. It works for arrays, lists, and other collection types, and .. spreads another
collection's items in.
FWhat is a raw string literal, and when is it useful?concept
Text between three double quotes ("""), where quotes and backslashes need no escaping and the
closing quotes' indentation is removed. It suits SQL, JSON, and other text with quotes; values still
belong in SQL parameters.
FWhat does the C# 14 field keyword do?concept
Inside a property accessor, field refers to the property's compiler-made backing field, so a
property with a custom setter, such as trimming or validation, no longer needs a hand-written
private field.
MWhat are list patterns?concept
Patterns that match the shape of a sequence: ["Absent", ..] (first item is Absent),
[.., "Absent", "Absent"] (last two), [_, _, _] (exactly three items). _ matches one item and
.. any number of items.
MHow do primary constructors on classes differ from records?concept
Both declare parameters after the type name. A record turns them into public init-only properties with value equality. A class with a primary constructor only makes the parameters available inside the class body; they are not properties, and they are not read-only.
MWhat are C# 14 extension members?concept
An extension(Type receiver) { ... } block inside a static class that can declare extension
properties as well as methods, such as student.Initials. Before C# 14, only extension methods
were possible.
SA developer converted half the codebase to new C# syntax in one pull request. How do you handle it?scenario
Ask to split it: a large mechanical change hides real changes and is hard to review. Agree on which features the team adopts, apply them in new and changed code, and convert old code gradually or with automated, separately reviewed refactorings.
Balance modernization against reviewability and risk. Mention coding standards, analyzers or editorconfig rules, and keeping behavior changes separate from style changes.
SShould a switch over an enum end with a default arm? What are the trade-offs?design
Without _, the compiler warns about missing statuses (CS8509) and unnamed values (CS8524), which
helps when new statuses are added. A quiet default hides new statuses. A common choice is to list
every status and end with _ => throw, so unexpected values fail loudly.
Explain both warnings, the risk of silent defaults, and the throwing default as a middle path.
AHow would you keep a large codebase current with new .NET and C# versions?design
Upgrade to each LTS release on a plan, update the target framework and packages, fix analyzer warnings, and adopt new language features through agreed coding standards in new and changed code. Automated tests make upgrades safe, and editorconfig or analyzers keep the style consistent.
Cover the upgrade cadence (LTS), risk control (tests, staged rollout), and team practices for adopting features. Mention support end dates as the business driver.
async and await
FWhat do async and await do?concept
async marks a method that can use await and returns Task or Task<T>. await pauses the
method until a task completes, giving the thread back in the meantime, and continues from the same
line afterwards.
FWhat is the difference between Task and Task<T>?concept
Both represent work that finishes later. Task has no result, like writing a log file;
Task<T> produces a value of type T, like Task<string> for a send status.
FDoes async make code run faster?concept
Not by itself. It makes waiting for I/O cheaper by freeing threads, which improves scalability and lets independent waits overlap. CPU-bound calculations need parallelism instead.
MHow do you run several independent async operations together?coding
Start them without awaiting, collect the tasks, and await Task.WhenAll(tasks). Ten 250 ms sends
took about 260 ms together instead of 2.6 seconds one by one. Results come back in the same order.
MWhat is a CancellationToken, and why pass it through async methods?concept
A token that signals that work should stop, created by a CancellationTokenSource, for example with
a time limit. Passing it down to every async call lets the whole operation stop early; ASP.NET Core
cancels it when the client disconnects.
MWhy should you avoid async void?concept
An async void method cannot be awaited, so callers cannot know when it ends, and exceptions it
throws cannot be caught by the caller and can crash the process. Return Task instead; use
async void only for event handlers.
SA web portal stops responding under load, but the CPU is nearly idle. The code uses .Result on database calls. What is happening?scenario
Thread pool starvation: each request blocks a thread while waiting for the database, so the pool
runs out and new requests queue. Make the call chain async all the way with await, so threads are
released during waits.
Explain the symptom (low CPU, high latency), the cause (blocked threads), the fix, and how to confirm it with thread pool counters or dotnet-counters.
SHow are exceptions handled with Task.WhenAll?concept
WhenAll waits for all tasks to finish, then await rethrows the first exception; the other
tasks still complete. Inspect each task's status or the aggregate Exception to see all failures,
and design batches so one failure does not stop the rest.
Show awareness that only the first exception surfaces through await, and how to collect all errors for reporting in batch jobs.
AHow would you send fee reminders to 10,000 families reliably and quickly?design
Send asynchronously with limited concurrency (for example batches or a semaphore) so the provider is not overwhelmed, with timeouts and cancellation, retries for temporary failures, and a record of what was sent so a restart does not send twice. Run it as a background job, not inside a web request.
Cover throughput (bounded concurrency), reliability (retries, idempotency, persistence), provider limits, and observability. Mention background workers in Module 12.
Threading
FWhat is the difference between a thread and a task?concept
A thread is a path of execution managed by the operating system. A task is a unit of work that
.NET schedules, usually on a reusable thread-pool thread. Modern code uses tasks, Parallel, and
async instead of creating threads by hand.
FWhat is a race condition?concept
A bug where the result depends on the timing of threads that share data. Two threads doing
count++ can both read the same value and write the same result, losing an update; one million
increments gave about 62,000.
FWhat does Parallel.ForEach do?concept
It processes the items of a collection on several thread-pool threads at once, using multiple cores. It suits CPU-bound, independent work, such as building 1,006 report cards about three times faster on 16 cores.
MWhen would you use Interlocked instead of lock?concept
Interlocked performs a single update on one number, such as increment or add for int and
long, as one uninterruptible step, without blocking. Use lock when several fields change
together, for types like decimal, or for collections.
MWhy might parallel code be much less than N times faster on N cores?concept
Splitting and combining work costs time, cores share memory bandwidth, locks make threads wait, and parts of the program run on one thread only (Amdahl's law). Very small work items can even be slower in parallel.
MIs Dictionary thread-safe? What do you use instead?concept
No: adding from several threads at once can lose items or corrupt it. Use ConcurrentDictionary
(or other System.Collections.Concurrent types), or let each thread build its own results and
combine them afterwards.
SA parallel term-end report gives a slightly different fee total each run. What is wrong, and how do you fix it?scenario
Threads add to one shared total without protection, so updates are lost in a race. Fix it by computing independent partial totals per section or thread and adding them at the end, or by protecting the shared total with a lock. Then test repeatedly with production-sized data.
Recognise the symptom of nondeterminism, name the race, give the share-nothing fix first and the lock as an alternative, and mention why such bugs pass normal tests.
SWhat is a deadlock with locks, and how do you avoid one?concept
Two threads each hold one lock and wait for the lock the other holds, so both wait forever. Avoid it by taking locks in a fixed order, keeping locked sections small, avoiding nested locks, and never awaiting or calling unknown code while holding a lock.
Explain the circular wait, prevention rules, and diagnosis with a debugger or dump showing thread stacks. Relate it to the SQL deadlocks of Lesson 25.
AHow do you design a web application so that concurrent requests do not corrupt shared state?design
Keep request handling stateless: per-request objects, no mutable static fields, data in the database with transactions and constraints. Where in-memory sharing is needed, such as caches, use thread-safe types and immutable data, and keep heavy CPU work in background jobs.
Cover the request model (many threads), where state should live, synchronization choices, and service lifetimes in dependency injection (singleton services must be thread-safe).
Memory and GC
FWhat is the difference between the stack and the heap?concept
The stack holds method-local value-type variables and references, freed automatically when a method returns. The heap holds objects such as class instances, arrays, and strings, freed by the garbage collector when nothing references them.
FWhat does the garbage collector do?concept
It periodically finds objects that running code can no longer reach and reclaims their memory, then compacts the surviving objects. Developers do not free managed memory by hand.
FWhat is IDisposable, and what does using do?concept
IDisposable has one method, Dispose, which releases resources the GC does not manage, such as
files and connections. using calls Dispose automatically at the end of a block, even if an
exception is thrown.
MWhat are GC generations?concept
Generation 0 holds new objects and is collected often; survivors move to generation 1, then to generation 2, which is collected rarely. Most objects die young, so this makes collection cheap. Objects of 85,000 bytes or more start on the large object heap, counted as generation 2.
MWhat is the difference between Dispose and a finalizer?concept
Dispose releases resources at a known moment, called by your code or using. A finalizer runs
when the GC collects the object, at an unknown time, on a special thread, and delays collection.
Prefer Dispose; modern code rarely writes finalizers because SafeHandle covers them.
MHow can events cause memory leaks?concept
An event holds delegates, and each delegate references its subscriber. If a long-lived object's
event keeps a short-lived subscriber, the subscriber cannot be collected until it unsubscribes.
Unsubscribe with -=, often in the subscriber's Dispose.
SAn API's memory grows every day until it needs a restart. How do you investigate?scenario
Watch memory and GC counters over time, take memory snapshots at two points, and compare which object types grow and what keeps them alive. Typical culprits are event subscriptions on long-lived services, static collections, unbounded caches, and undisposed resources.
Describe a measured approach (dotnet-counters, dumps or Visual Studio snapshots, retention paths), the common causes, and verifying the fix under load.
SShould you call GC.Collect() in application code?concept
Almost never. The GC tunes its own timing, and forcing collections usually costs performance by promoting objects and pausing the program. It is useful in experiments and tests that measure memory, as in this lesson.
Explain the cost, the rare legitimate cases, and what to do instead: fix the cause of memory growth.
AHow do you design a high-traffic .NET service to be memory-efficient?design
Stream large data instead of loading it, avoid many short-lived large objects, reuse buffers (pooling), bound every cache, dispose resources promptly, avoid long-lived references to per-request objects, and monitor GC metrics in production.
Cover allocation patterns, lifetimes, pooling, caching limits, and observability, with an example such as exporting attendance for a whole school.