Interview Preparation

Answers are short on purpose: say the key idea first, then give an example.

Concept

Answers are short on purpose: say the key idea first, then give an example. The module ends with classic "what does this print?" questions verified by running them.

A modern, statically typed, object-oriented and functional language by Microsoft, compiled to IL and run on .NET (Module 1)

A free, cross-platform runtime (CLR + JIT + GC) plus libraries, SDK and tools for building all kinds of applications What is a variable?

A named storage location with a type: int speed = 120; Value type vs reference type?

Value types (int, struct) hold data directly and are copied on assignment; reference types (class, string, arrays) hold a reference to a heap object (Module 5) var vs dynamic?

var is compile-time type inference (still static); dynamic defers member binding to run time (Module 37) What is a class? An object?

A class is a blueprint (fields, properties, methods); an object is an instance created with new What is inheritance?

A class derives from a base class, reusing and specializing it (class Car: Vehicle) What is encapsulation?

Hiding internal state behind a public interface (private fields, properties with validation) Interface vs abstract class?

Interface: a contract, multiple inheritance, default members possible, no instance state. Abstract class: shared state and implementation, single inheritance, constructors (Module 16) ref vs out?

ref requires an initialized variable and may read/modify it; out need not be initialized and must be assigned by the method IEnumerable vs ICollection?

IEnumerable<T> only enumerates; ICollection<T> adds Count, Add, Remove, Contains IEnumerable vs IQueryable?

IEnumerable<T> runs delegates in memory; IQueryable<T> builds expression trees that a provider translates (e.g. to SQL) (Module 38)

Language-integrated query: composable query operators over sequences (Module 24) What is deferred execution?

Most LINQ queries run only when enumerated, and every enumeration re-runs them What is boxing?

Wrapping a value type in an object on the heap (object o = 42;); unboxing copies it back; costs allocations What is garbage collection?

Automatic memory management: the GC finds unreachable objects and reclaims them; generational and compacting (Module 30) What is dependency injection?

Supplying a class's dependencies from outside (usually via the constructor) so it depends on abstractions (Module 45) How does async/await work?

The compiler turns an async method into a state machine; await on an incomplete task registers a continuation and returns; the thread is free while I/O is pending (Module 31) What is a synchronization context?

An abstraction for "where continuations run" — the UI thread in WPF/WinForms; ASP.NET Core and console apps have none (Module 32) What causes deadlocks?

Circular waits: lock ordering violations, or blocking (.Result) on a task whose continuation needs the blocked thread (UI context) What is Span<T>?

A stack-only (ref struct) view over contiguous memory for allocation-free slicing and parsing (Module 41) What is Memory<T>?

The heap-storable counterpart of Span<T> usable in async code and fields How does the GC work?

Generations 0/1/2 + LOH/POH; mark reachable objects from roots, sweep/compact; gen 0 collections are cheap and frequent What are expression trees?

Code represented as data (Expression<Func<...>>) that can be inspected, translated or compiled (Module 38) What are source generators?

Compiler plugins that add source code during compilation — no run-time reflection cost (Module 39) How does JIT compilation work?

IL is compiled to native code per method on first call; tiered compilation starts quick (tier 0) and recompiles hot methods optimized (tier 1, with PGO); ReadyToRun/Native AOT precompile (Module 1) What is covariance/contravariance?

out T: IEnumerable<string> → IEnumerable<object>; in T: IComparer<object> → IComparer<string> (Module 40) How do you diagnose high memory usage?

dotnet-counters to confirm growth, dotnet-gcdump/dotnet-dump to find the largest types and gcroot to find who holds them (Module 57)

How would you design a high-throughput C# service?

Async I/O end to end, bounded channels with backpressure, batching, pooled buffers and spans, minimal locking (partitioning), caching, horizontal scaling behind a load balancer, measured with benchmarks and production metrics How would you reduce allocations?

Measure (MemoryDiagnoser, allocation profiler), then: spans instead of substrings, ArrayPool, pre-sized collections, structs/readonly record struct, avoid LINQ/closures in hot paths, StringBuilder/string.Create, source-generated serializers/logging

How would you investigate thread-pool starvation?

Symptoms: rising latency with low CPU; dotnet-counters shows a growing thread-pool queue and slowly increasing thread count; dump with dotnet-dump and look for many threads blocked in .Result/Wait; fix sync-over-async

How would you design a plugin architecture?

Plugin contract assembly with interfaces; load plugins with AssemblyLoadContext (isolation/unloading); discover via reflection or a manifest; version the contract; sandbox untrusted plugins in separate processes

How would you design a distributed diagnostic system?

Bench agents near hardware, central services for devices/tests/results, a message broker for jobs and results, idempotent consumers, outbox, OpenTelemetry tracing, resilience policies, auth with roles (Module 64 expert capstone)

How would you make an API backward compatible?

Only add (members, optional properties, overloads), never remove or change behaviour in minor versions; [Obsolete] with migration guidance; API versioning for HTTP; package validation in CI (Module 60)

How would you design a resilient async pipeline?

Channels between stages, bounded capacity, per-stage error handling with retries for transient errors and dead-letter for poison items, cancellation propagation, timeouts, metrics per stage, graceful shutdown that drains queues

Why It Matters

Interviews test both knowledge and the ability to explain it concisely. Practising answers aloud — with an example from your own projects — is the most effective preparation.

Syntax

Answer pattern: definition → why it matters → example → trade-off.

Example

65.1 Classic "what does this print?" questions

// Classic interview questions, answered by running the code

// Q: string immutability and interning
string s1 = "VCU"; string s2 = s1; s1 += "!";
Console.WriteLine($"1. s2 after s1 += \"!\": {s2}; literal \"VCU\" interned: {ReferenceEquals("VCU", s2)}");

// Q: value vs reference type assignment
var p1 = new PointStruct { X = 1 }; var p2 = p1; p2.X = 2;
var c1 = new PointClass { X = 1 }; var c2 = c1; c2.X = 2;
Console.WriteLine($"2. struct copy: p1.X={p1.X}; class reference: c1.X={c1.X}");

// Q: boxing
int n = 42; object boxed = n; n = 7;
Console.WriteLine($"3. boxed copy unaffected: {boxed}; (int)boxed == n: {(int)boxed == n}");

// Q: ref vs out vs in
int value = 1;
AddRef(ref value); MakeOut(out int created);
Console.WriteLine($"4. ref modified the caller's variable: {value}; out created: {created}");

// Q: deferred execution
var source = new List<int> { 1, 2, 3 };
var query = source.Where(x => x > 1);
source.Add(4);
Console.WriteLine($"5. deferred LINQ sees later changes: {string.Join(",", query)}");

// Q: closures capture variables
var actions = new List<Func<int>>();
for (int i = 0; i < 3; i++) actions.Add(() => i);
Console.WriteLine($"6. for-loop closures capture the si
…

Expected Result

1. s2 after s1 += "!": VCU; literal "VCU" interned: True
2. struct copy: p1.X=1; class reference: c1.X=2
3. boxed copy unaffected: 42; (int)boxed == n: False
4. ref modified the caller's variable: 11; out created: 99
5. deferred LINQ sees later changes: 2,3,4
6. for-loop closures capture the single variable i: 3,3,3
   foreach gets a fresh variable per iteration (C# 5+): 0,1,2
7. override via base reference: Derived, 'new' method hides only for Derived references: Base / Derived
8. static constructor ran before the first access to Order.Log
9. IQueryable holds an expression: System.Int32[].Where(x => (x > 1))
10. object == compares references: False; Equals compares values: True
11. finally runs first
11. caught 'boom' after finally ran

Common Mistakes

Memorized definitions without examples or trade-offs.

Saying "I don't know" without reasoning aloud — interviewers want to see your thinking.

Over-claiming experience with tools you have only read about.

Not asking clarifying questions in design problems.

Best Practices

Prepare 3–4 project stories (a bug you found, a performance improvement, a design decision, a failure you learned from).

Practise live coding with a timer; talk while you code.

For design questions: clarify requirements, sketch components, discuss data flow, failure modes and scaling.

Review the Quick Quiz sections of this course — they mirror common questions.

Practice Questions

Explain the difference between Task.Run and async/await to a beginner in two minutes.

Draw the architecture of the expert capstone and explain how a test job flows through it.

Explain why for loop closures print 3,3,3 and how to fix it.

Prepare an answer to "tell me about a production issue you debugged".

Quick Quiz

Q1. (Predict the output) var list = new List<int>{1,2,3}; var q = list.Where(x => x > 1); list.Add(4); Console.WriteLine(string.Join(",", q));

Answer: 2,3,4 — deferred execution (verified).

Q2. (Multiple choice) Base b = new Derived(); b.Hidden(); where Derived declares public new string Hidden(). Which method runs? A) Derived.Hidden B) Base.Hidden C) Compile error D) Both

Answer: B (verified: Base); only override dispatches virtually.

Q3. (True/False) Changing a boxed copy changes the original int.

Answer: False. Boxing copies the value (verified: the boxed value stayed 42).

Q4. (Find the bug) for (int i = 0; i < 3; i++) tasks.Add(Task.Run(() => Process(i)));

Answer: All lambdas capture the same i, which may be 3 when they run; copy it first (int copy = i;) or use foreach/Parallel.For.

Coding Challenge

Without running it, predict the output; then verify: object a = 1; object b = 1; Console.WriteLine($"{a == b} {a.Equals(b)} {(int)a == (int)b}"); Output: False True True.

object a = 1; object b = 1;
Console.WriteLine($"{a == b} {a.Equals(b)} {(int)a == (int)b}");   // two separate boxes: reference comparison is False