
Most C# interviews are won or lost on the same six topics: value vs reference types, boxing, how async/await actually works, LINQ's deferred execution, delegates vs events, and garbage collection. Get those right with one concrete example each, and you've already cleared the bar that most candidates trip over. This guide gives you the question, a short correct answer, and the follow-up the interviewer is really fishing for.
Here's the map:
- Type system — value vs reference types, boxing/unboxing, equality
- Async and concurrency —
Task,async/await, when to useTask.Run - LINQ — deferred execution,
IEnumerablevsIQueryable, the common bug - Delegates, events, and generics — what they are and when each fits
- Garbage collection — generations, promotion,
IDisposable - Prep tips — how to study so the answers come out clean under pressure
C# type system: the questions that filter everyone
C#) is a statically typed, object-oriented language, and interviews almost always open here. The questions are part definitional ("what is X?") and part applied ("here's code — what does it print?").
What's the difference between value types and reference types?
A variable of a value type holds its data directly. A variable of a reference type holds a reference to data that lives on the managed heap.
- Value types —
int,bool,double,enum,struct,DateTime. Assignment copies the value, so two variables are independent. - Reference types —
class,string,object, arrays, delegates. Assignment copies the reference, so two variables can point at the same instance and a mutation through one is visible through the other.
The classic gotcha: string is a reference type but behaves like a value type for equality — == compares contents, not references, and strings are immutable. Mentioning that unprompted signals you actually understand the model.
What is boxing and unboxing, and why does it matter?
Boxing is the conversion of a value type to object (or to an interface it implements). The runtime allocates an object on the heap and copies the value into it. Unboxing extracts the value back out. Boxing is implicit; unboxing is explicit and requires a cast.
int i = 123;
object o = i; // boxing — heap allocation, value copied
int j = (int)o; // unboxing — explicit castTwo points that earn credit:
- Boxing is expensive — it allocates a new heap object every time, so doing it in a tight loop creates GC pressure.
- Unboxing to the wrong type throws
InvalidCastException. UnboxingnullthrowsNullReferenceException.
The practical takeaway: generics eliminate boxing for value types. List<int> stores ints directly; the old non-generic ArrayList boxed every element. Microsoft's boxing and unboxing reference is the canonical source if you want to ground the answer in the docs. This same type-system question shows up across the broader .NET interview loop, so it's worth nailing once.
Async and concurrency
This is where mid-level interviews separate from junior ones. Candidates who can explain what await actually *does* — rather than just where to type it — stand out immediately.
How do async and await work?
Task and Task<T> model an operation that may not have finished yet. The async keyword lets you use await inside a method; await yields control back to the caller until the task completes, then resumes the method where it left off. Under the hood, the compiler rewrites the method into a state machine that tracks where to resume.
The detail interviewers want: await does not block a thread. While an I/O operation is in flight, the calling thread is free to do other work. That's why async scales web servers and keeps UIs responsive. Microsoft's asynchronous programming scenarios walks through both the I/O-bound and CPU-bound cases.
When should you use Task.Run?
Only for CPU-bound work. The rule of thumb:
| Scenario | What to do |
|---|---|
| I/O-bound (database, HTTP, file read) | await the async API directly — no Task.Run |
| CPU-bound (heavy calculation) | Offload with await Task.Run(...) to free the calling thread |
| Blocking on a result is unavoidable | Prefer GetAwaiter().GetResult() over .Result/.Wait() |
A frequent trap: wrapping an already-async I/O call in Task.Run. That just burns a thread-pool thread for no benefit. Another one: calling .Result or .Wait() on a UI or request context, which can deadlock — await all the way up the call stack instead.
What does async void do, and when is it acceptable?
async void is fire-and-forget: the caller can't await it, and exceptions thrown inside it can't be caught from outside. Use it only for event handlers, where the signature forces void. Everywhere else, return Task or Task<T> so callers can await and handle errors.
LINQ: deferred execution and the IQueryable trap
LINQ questions test whether you understand *when* a query runs, not just how to write one.
What is deferred execution?
A LINQ query is a description, not a result. Operators like Where and Select build the query but don't run it. Execution happens only when you enumerate — foreach, ToList(), ToArray(), First(), Count(), Any(). The same query can run twice and return different results if the underlying data changed in between. That's why mixing async with LINQ is risky: the async calls don't fire until the sequence is iterated.
What's the difference between IEnumerable and IQueryable?
Both are lazy, but they execute in different places.
IEnumerable<T> | IQueryable<T> | |
|---|---|---|
| Evaluation | In process (LINQ to Objects) | At the data source (translated to SQL, etc.) |
| Mechanism | Delegates — each operator is a method call | Expression tree a provider translates |
| Best for | In-memory collections, streaming large sequences | Database queries via EF Core |
The single most common LINQ performance bug: calling .ToList() or .AsEnumerable() on an IQueryable too early. That ends translation and pulls every row into memory, so any Where after it filters in C# instead of in the database. Keep filtering and paging on the IQueryable and materialize last. This exact pattern comes up constantly in data engineer interview questions when query efficiency is on the table.
Delegates, events, and generics
These three round out the C# fundamentals section of most interviews.
What's the difference between a delegate and an event?
A delegate is a type-safe reference to a method — think a function pointer you can pass around, store, and invoke. An event is built on top of delegates but restricts access: outside classes can only += (subscribe) and -= (unsubscribe); only the declaring class can raise it.
Microsoft's own delegates vs. events guidance gives the cleanest heuristic: if your code must call the supplied method to do its job (like a List.Sort comparer or a LINQ predicate), use a delegate. If your code completes its work whether or not anyone is listening (progress reporting, UI clicks), use an event.
What are generics and what problem do they solve?
Generics let you write a type or method parameterized by type — List<T>, Dictionary<TKey, TValue> — so the same logic works for any type with full compile-time type safety and no boxing for value types. Before generics, collections stored object, which meant casting on the way out and boxing for value types. Generics removed both costs. The common follow-ups are about constraints (where T : class, where T : IComparable<T>) and the generic Func<>, Action<>, and EventHandler<TEventArgs> delegates.
Garbage collection
GC questions check whether you understand memory without leaning on it. You won't manage memory manually, but you're expected to know how the CLR does it.
How does the garbage collector work?
The CLR's garbage collector is an automatic memory manager. It builds a graph of objects reachable from roots — static fields, local variables on the stack, CPU registers, GC handles — and reclaims everything not in that graph. Surviving objects are compacted so the heap stays contiguous and allocation stays fast.
What are GC generations?
The managed heap is split into three generations to collect short-lived objects cheaply:
- Generation 0 — newly allocated, short-lived objects. Collected most often.
- Generation 1 — a buffer between short- and long-lived objects.
- Generation 2 — long-lived objects (and the large object heap).
Objects that survive a collection are promoted to the next generation: gen 0 survivors move to gen 1, gen 1 survivors to gen 2, and gen 2 survivors stay. A gen 2 collection is a full collection because it sweeps every generation, which is why it's the most expensive. Microsoft's garbage collection fundamentals is the reference to cite.
If GC is automatic, why does IDisposable exist?
The GC manages memory, but it doesn't know how to release unmanaged resources — file handles, sockets, database connections. IDisposable.Dispose() gives you a deterministic way to release those immediately, and the using statement calls Dispose() for you when the block exits. This distinction — managed memory vs unmanaged resources — is a reliable senior-level follow-up.
How to prepare so the answers come out clean
Knowing the material and performing it under pressure are different skills. A few tactics that work:
- Say the definition, then the example. "Boxing wraps a value type on the heap — like assigning an
inttoobjectin a loop, which allocates each time." One sentence plus one concrete case beats a vague paragraph. - Practice the "what does this print?" format. Pull a few snippets on value-type copying, closure capture, and deferred LINQ execution. These are the trick questions.
- Build a written cheat sheet for the six core topics above and rehearse them out loud. The broader technical interview and system design loops reward the same habit — short, structured answers with a real example attached.
- Mock the interview. Reading answers is passive; saying them is active. Run a few rounds with a peer or a tool, and review where you stalled.
Research the person, not just the topics
Technical depth gets you through the questions in this guide. What separates two equally qualified candidates is often rapport — and that comes from knowing who's across the table. Articuler helps you find the actual hiring manager or interviewer behind a role and build a Playbook on their background and what they care about, so you walk in prepared for *that* conversation, not a generic one. It also drafts a personalized outreach note that gets roughly 8x the reply rate of a generic message — useful when you'd rather reach the team directly than wait in the ATS queue.
Key takeaways
- The six topics that decide most C# interviews: value vs reference types, boxing,
async/await, LINQ deferred execution, delegates vs events, and GC generations. - Value types copy their data; reference types copy a reference. Boxing moves a value type to the heap and costs an allocation — generics avoid it.
awaityields a thread rather than blocking it; useTask.Runonly for CPU-bound work and avoid.Result/.Wait()to dodge deadlocks.- LINQ runs only when enumerated; materializing an
IQueryabletoo early is the most common performance bug. - The GC reclaims unreachable objects across three generations;
IDisposableexists for the unmanaged resources it can't clean up. - Prepare by pairing each definition with one concrete example, and rehearse out loud — clean delivery under pressure is its own skill.
Frequently asked questions
What are the most common C# interview questions?
The most common C# interview questions cover value vs reference types, boxing and unboxing, async/await, LINQ deferred execution, the difference between IEnumerable and IQueryable, delegates vs events, generics, and how garbage collection works. Junior loops stay definitional; senior loops add performance, memory, and design follow-ups.
Are C# and C Sharp interview questions the same thing?
Yes. "C Sharp" is just the spelled-out name of C#, so C Sharp interview questions and C# interview questions refer to the same set of topics — the language's type system, async model, LINQ, delegates, and runtime behavior.
What's the difference between IEnumerable and IQueryable?
IEnumerable<T> evaluates in memory using delegates, so it's right for in-memory collections. IQueryable<T> builds an expression tree a provider (like EF Core) translates to SQL and runs at the database. Filter on the IQueryable and materialize last, or you'll pull every row into memory.
Does the garbage collector make memory management automatic in C#?
It automates memory cleanup for managed objects across three generations, so you rarely free memory manually. But it doesn't handle unmanaged resources like file handles or connections — that's what IDisposable and the using statement are for.