Previously, in the roadmap post, we mapped the whole .NET interview loop and saw that interviewers reward understanding over recitation. Now we get to work. This part covers the five C# language questions that appear in nearly every technical round — and, more importantly, the understanding that survives the follow-ups.
"What's the difference between a value type and a reference type?"
Why they ask it: This is the single most common C# question, and it's a trap for the memorizers. Everyone can recite "stack vs heap." The interviewer is checking whether you know what that recitation misses — the semantics — because those semantics cause real bugs.
A strong answer: The honest version first: where things are stored (stack vs heap) is an implementation detail, and it's not even always true — a value type field inside a class lives on the heap with its owner. What actually matters is copy semantics. Assigning a value type copies the data itself, so you get two independent values. Assigning a reference type copies a reference, so two variables now point at one shared object. Every surprise in this area traces back to that difference:
struct PointStruct { public int X; }
class PointClass { public int X; }
var s1 = new PointStruct { X = 1 };
var s2 = s1; // full copy
s2.X = 99;
Console.WriteLine(s1.X); // 1 — s1 is untouched
var c1 = new PointClass { X = 1 };
var c2 = c1; // same object, two names
c2.X = 99;
Console.WriteLine(c1.X); // 99 — "spooky action" if you expected a copy
Lead with semantics, mention storage as the footnote, and you've flipped the usual answer on its head — in a way interviewers notice.
Try it: Paste the code above into your console app. Then change PointStruct to store its X in a class field's property and predict, before running, which lines print 1 and which print 99. Being able to predict this cold is the skill being tested.
Follow-ups to expect:
- "Is a string a value type or a reference type?" — Reference type, but immutable, so it feels like a value.
- "What happens when you pass a struct to a method?" — It's copied, so mutations inside the method don't leak out (unless you use
ref). - "Where does a struct field of a class live?" — On the heap, inside the object — proof that "structs live on the stack" is a simplification.
Red flag: Answering only "value types go on the stack, reference types go on the heap" and stopping. It's the memorized line, it's incomplete, and the very first follow-up will find that out.
"Why are strings immutable, and what does that imply?"
Why they ask it: It sounds like trivia, but it tests whether you connect a language design decision to its practical consequences — the "why, not just what" signal from Part 1.
A strong answer: Once a string is created, it can never change; every "modification" produces a brand-new string. This buys safety — strings can be shared across threads, used as dictionary keys, and passed around freely without anyone mutating them behind your back. It also enables interning: identical string literals can share one instance because nobody can alter it.
The implication interviewers want to hear: concatenation in a loop is quietly expensive,
because each pass allocates a whole new string and copies everything so far. That's the
job StringBuilder exists for — it maintains a mutable buffer and builds the
string once at the end.
var s = "";
for (var i = 0; i < 10_000; i++)
{
s += i; // ~10,000 allocations, each copying the whole string
}
var sb = new StringBuilder();
for (var i = 0; i < 10_000; i++)
{
sb.Append(i); // one growing buffer
}
var result = sb.ToString();
Try it: Wrap both loops above in Stopwatch timings and crank the count to 100,000. The gap isn't subtle — and now you have a number to quote in interviews instead of a vague "it's slower."
Follow-ups to expect:
- "So is a handful of + concatenations bad?" — No; the compiler and runtime handle small cases fine. It's loops that hurt.
- "What is string interning?" — The runtime keeps a pool of unique strings so identical literals share one instance.
- "Why are immutable types nice for dictionary keys?" — The hash code can't change while the key sits in the dictionary.
Red flag: "You should always use StringBuilder instead of +." Always-rules signal cargo-culting; the real answer is about when allocation cost compounds.
"What is boxing, and when does it bite?"
Why they ask it: Boxing sits exactly on the seam between value and reference types, so it confirms you really understood question one — and it tests whether you can spot hidden allocations in innocent-looking code.
A strong answer: Boxing is what happens when a value type is converted to
object (or to an interface it implements): the runtime allocates a box on the
heap and copies the value into it. Unboxing casts it back out. Each box is a small heap
allocation — harmless once, painful a million times in a hot loop.
int n = 42;
object o = n; // boxed: heap allocation, value copied in
int back = (int)o; // unboxed: value copied back out
Where it bites: the old non-generic collections like ArrayList and
Hashtable store object, so every int you add gets boxed — which
is a big part of why generics were added and why List<int> stores ints
with no boxing at all. Modern bites are sneakier: string formatting that takes
object parameters, or calling an interface method through an interface-typed
variable that holds a struct.
Try it: Add an int to an ArrayList and to a List<int>, then read both back. The ArrayList makes you cast — that cast is the unboxing, visible in your own code. The generic list never needed the box.
Follow-ups to expect:
- "How would you find boxing in a real codebase?" — A profiler showing allocation hot spots, or analyzer warnings.
- "Does putting a struct into an interface-typed variable box it?" — Yes; the interface reference needs a heap object to point at.
- "Why did generics largely solve this?" —
List<int>is specialized for int, so values are stored directly.
Red flag: Defining boxing correctly but being unable to name a single place it actually occurs. The definition is the flashcard; the examples are the understanding.
"Interface vs abstract class — when would you use each?"
Why they ask it: This is a design-judgment question wearing a trivia costume. Listing feature differences is table stakes; the interviewer wants to hear you reason about intent.
A strong answer: An interface declares a contract:
"anything that can do X." An abstract class provides a shared base:
"these things are all a kind of Y, and here's the common machinery." A class can implement
many interfaces but inherit only one base class, which is itself a design hint — capabilities
are many, identity is singular. So: use an interface when unrelated types need a common
capability (IComparable, IDisposable); use an abstract class when
a family of types shares real implementation and state.
Do mention that interfaces can now have default method implementations — it shows your knowledge is current — but immediately add that this doesn't erase the design distinction. Default interface methods are mainly for evolving published APIs without breaking implementers; an abstract class is still the natural home for shared state and protected helpers. The design answer, not the feature list, is what they're grading.
Try it: Sketch a payment system with CardPayment, BankTransfer, and WalletPayment. Decide what belongs in an IPaymentMethod interface versus a PaymentBase abstract class (shared validation? audit logging?). There's no single right split — practicing the justification is the exercise.
Follow-ups to expect:
- "Why might you prefer an interface even when an abstract class would work?" — Looser coupling and far easier testing/mocking.
- "When have default interface methods helped you?" — Adding a member to a widely-implemented interface without breaking everyone.
- "Can an abstract class have a constructor?" — Yes; derived classes call it, even though you can't instantiate the abstract class directly.
Red flag: "An interface can't have any implementation" — outdated for years now — or reciting a feature-difference table with no opinion about when you'd choose either.
"What do records give you over classes?"
Why they ask it: Records are the modern-C# checkpoint: the question separates people who've kept up from people whose C# froze a decade ago. It also loops back — again — to value-versus-reference semantics.
A strong answer: A record is a class (or struct) with value-based behavior generated for you. Three headline gifts: value equality — two records with equal contents are equal, whereas two class instances are only equal if they're the same object; with-expressions — non-destructive mutation that copies a record with some properties changed; and immutability by default via concise positional syntax and init-only properties.
public record Money(decimal Amount, string Currency);
var a = new Money(10m, "USD");
var b = new Money(10m, "USD");
Console.WriteLine(a == b); // True — value equality
var c = a with { Amount = 25m }; // new record, a is unchanged
Console.WriteLine(a.Amount); // 10
Just as important: knowing when not to use them. Entities with an identity and a
mutable lifecycle — an EF Core Customer whose row is tracked by primary key —
fit classes better, because there value equality is actively wrong: two snapshots of the
same customer at different times shouldn't compare equal, and ORMs track identity, not
contents. Records shine for values: money, coordinates, DTOs, configuration.
Try it: Recreate Money as a plain class with the same two properties and compare two equal-valued instances with == and Equals. Watching the class say "not equal" where the record said "equal" makes the whole feature click.
Follow-ups to expect:
- "Are records immutable?" — By convention and default syntax, yes; but you can declare mutable properties, so it's a default, not a law.
- "What does a with-expression actually do?" — Calls a generated clone, then applies your property overrides to the copy.
- "Record class vs record struct?" — Record structs add value-type copy semantics on top of the value equality.
Red flag: "Records are just shorter syntax for classes." That misses the entire point — the equality and immutability semantics — and suggests the candidate has read about records but never used one.
Where to next
Five questions, one common thread: semantics beat storage details, and "why" beats "what." If C# fundamentals still feel shaky in places, my post on why C# is a great first language is a gentler on-ramp to the same ideas.
Next we hit the round that produces more interview sweat than any other: Part 3 — async/await Interview Questions (the Deadlock Special).