Seventy questions walk into every C# interview in roughly the same order — the runtime, the OOP pillars, the keyword traps, then async and LINQ. Here is the whole gauntlet with answers short enough to actually remember.
Somewhere between the campus placement season and the mid-year switch window, every .NET aspirant in India ends up cramming the same list: what is boxing, why throw ex is a trap, when a struct beats a class. This guide compresses the 70 questions interviewers actually rotate through in 2026 into answers of two to four sentences each — long enough to sound like you understand it, short enough to recall in the room. Sections run junior to senior, so freshers can stop after the keyword rounds while 3–5-year candidates should be fluent through async, LINQ and the design patterns at the end. Each answer flags the follow-up trap where one exists.
The course paired with this guide — the Ultimate C# Masterclass by Krystyna Ślusarczyk (4.7 on Udemy) — covers the same ground as these questions with hands-on exercises. The coupon code CP260817G1 is attached to every course link on this page, so the discounted price shows directly at Udemy checkout. If the code has lapsed, our Udemy coupons page lists the live replacements, re-verified daily.
A class is a blueprint that bundles data (fields, properties) and behaviour (methods, events) into one type. It defines what its objects know and can do; nothing exists in memory until you instantiate it with new.
Four pillars: encapsulation (hide state behind a controlled surface), abstraction (expose only what callers need), inheritance (derive specialised types from general ones) and polymorphism (one call site, many runtime behaviours). Interviewers usually follow up by asking for a real example of each — prepare one from your own project.
An object is a runtime instance of a class: allocated memory holding that instance's state, accessed through a reference. A hundred objects of one class share the method definitions but each carries its own field values.
A constructor is the method that runs when an instance is created, sharing the class name and returning nothing. C# has default (parameterless), parameterised, copy (by convention), static (runs once per type, initialises static state) and private constructors (used by singletons and factory patterns).
A destructor (finalizer, ~ClassName) runs when the garbage collector is about to reclaim the object — at a time you do not control. Modern C# rarely needs one: unmanaged resources should be wrapped in SafeHandle or released via IDisposable and using instead.
Managed. The compiler emits Intermediate Language (IL) which the CLR executes, providing garbage collection, type safety and exception handling. You can opt into unmanaged territory with unsafe blocks and pointers, but that is the exception, not the rule.
The CLR is .NET's execution engine. It JIT-compiles IL to machine code, manages memory and the garbage collector, enforces type safety, handles exceptions and mediates interop with native code. Every .NET language — C#, F#, VB — compiles to IL and runs on it.
The GC automatically reclaims heap memory that no live reference can reach. It is generational (gen 0, 1, 2): short-lived objects are collected cheaply and often, long-lived ones rarely. You almost never call GC.Collect() yourself — mention that in an interview and explain why (it disrupts the GC's own heuristics).
Value types (int, double, bool, struct, enum) hold their data directly and are copied on assignment. Reference types (classes, strings, arrays, delegates) store a reference to data on the heap — assignment copies the reference, so two variables can point at the same object.
A namespace groups related types and prevents name collisions — System.Text.Json and a third-party Json class can coexist. You import one with using; since C# 10 a namespace Foo; file-scoped declaration saves a level of indentation.
Keeping a type's state private and exposing it only through a deliberate surface — properties, methods — so invariants can't be broken from outside. In C# that means private fields, public properties with validation, and the narrowest access modifier that works.
Showing callers the what and hiding the how. An IPaymentGateway interface with a Charge() method is abstraction; the card-network handshake behind it is implementation detail callers never see.
One name, many forms. Compile-time polymorphism is method overloading; runtime polymorphism is a base-class or interface reference invoking the override of whatever concrete type it actually points to, resolved through the virtual dispatch table.
A contract: members a type promises to implement, with no instance state. C# 8 added default interface methods, but the interview-safe answer is 'pure contract'. A class can implement many interfaces — this is how C# sidesteps multiple inheritance.
Deriving a class from a base class so it reuses and extends the base's members. C# supports single class inheritance (class Car : Vehicle), and sealed stops the chain. Favour composition when the relationship isn't a genuine 'is-a'.
Not for classes — one base class only, avoiding the diamond problem. A type may implement any number of interfaces, and default interface methods now give a limited mixin-like capability.
Both pass by reference. ref requires the variable to be initialised before the call and the method may read it; out needs no prior initialisation but the method must assign it before returning — the shape of int.TryParse(s, out var n).
== is resolved at compile time against the static types (reference equality for most classes unless overloaded); .Equals() is virtual and can be overridden for value semantics. Classic trap: string overloads == to compare content, so the two agree there but not for arbitrary objects.
Explicit interface implementation: void IA.Print() and void IB.Print() as separate bodies. The member is then reachable only through a reference typed as that interface, which resolves the ambiguity.
A virtual method has a body and may be overridden; an abstract method has no body, lives in an abstract class, and must be overridden by every concrete descendant.
Overloading: same name, different parameter lists, same type, chosen at compile time. Overriding: a derived class replaces a base virtual/abstract member with its own implementation, chosen at runtime.
static binds a member to the type rather than an instance — one copy shared program-wide. A static class can't be instantiated and holds only static members (think Math). Static constructors initialise type-level state exactly once.
No. this means 'the current instance', and static classes never have instances. The only place this appears in a static method's signature is the first parameter of an extension method — which is really syntax, not an instance reference.
const is a compile-time constant baked into every assembly that references it — change it and dependants must recompile. readonly is set at declaration or in a constructor, so it can differ per instance and hold runtime-computed values. Prefer readonly for anything that could ever change.
Strings are immutable — every concatenation allocates a new string. StringBuilder mutates an internal buffer, so building a string across many iterations goes from O(n²) copying to roughly O(n). Rule of thumb: loops and log assembly use StringBuilder; a handful of + joins don't need it.
break exits the nearest loop (or switch) entirely; continue abandons the current iteration and jumps to the next one. Neither crosses method boundaries — that's return's job.
Boxing wraps a value type in a heap object when it's treated as object; unboxing casts it back, with a runtime type check. Both cost allocations, which is exactly why generic collections (List<int>) replaced ArrayList.
A class that cannot be inherited from. Sealing communicates design intent, prevents fragile subclassing, and lets the JIT devirtualise calls. sealed on an override similarly stops further overriding.
One class split across several files, merged at compile time. Its main job is separating generated code from hand-written code — WinForms designers, EF scaffolding, source generators — so regeneration never clobbers your edits.
A named set of integral constants: enum Status { Pending, Shipped }. Cleaner and safer than magic numbers; decorate with [Flags] when values combine as bitmasks.
Instead of a class constructing its own dependencies, they are handed in — usually via the constructor — against interfaces. That decouples components, makes unit testing trivial (inject a mock) and centralises object wiring in a container; ASP.NET Core ships one with singleton, scoped and transient lifetimes.
Two meanings: a directive that imports a namespace, and a statement that guarantees Dispose() runs on an IDisposable even if an exception fires — using var conn = new SqlConnection(...). Interviewers want the second one and the phrase 'deterministic disposal'.
public (everyone), private (declaring type), protected (type + descendants), internal (same assembly), protected internal (either), private protected (both), and C# 11's file. Default for class members is private.
Type-safe references to methods with a matching signature — C#'s function pointers. They underpin events, callbacks and LINQ; in practice you use the built-in generic ones: Action (returns void), Func (returns a value), Predicate<T> (returns bool).
A delegate holding an invocation list of several methods, combined with +=; invoking it calls each in order. Events are multicast delegates with restricted access. For non-void delegates only the last result survives — a favourite follow-up question.
A fixed-length, zero-indexed, contiguous block of elements of one type. Fast indexed access, but resizing means allocating a new array — which is why growable scenarios use List<T> (itself array-backed).
Arrays are fixed-size with minimal overhead; List<T> wraps an array and grows it automatically (doubling capacity), adding Add/Remove/Insert. Use arrays for fixed-shape data and interop, List for everything that grows.
The minimal 'you can iterate me' contract — one method returning an enumerator. It's the type LINQ extends, supports deferred execution, and promises nothing about count or indexing. Return it from APIs when callers only need to read forward.
A hash table mapping unique keys to values with average O(1) lookup, insert and delete. Keys must implement solid GetHashCode/Equals; iteration order is unspecified — mention TryGetValue to avoid the double-lookup anti-pattern.
Structs are value types: copied on assignment, no inheritance, ideally small and immutable (DateTime, Point). Classes are reference types with inheritance and identity. Choose a struct when the type is small, short-lived and logically a single value; record struct makes that concise now.
Static methods whose first parameter carries this, letting you call them as if they were instance members of that type — without touching its source. All of LINQ (Where, Select) is extension methods on IEnumerable<T>.
An unordered collection of unique elements with O(1) membership tests, plus set algebra (UnionWith, IntersectWith). Reach for it whenever the question is 'have I seen this before?' rather than 'what's at index i?'
Type parameters on classes and methods — List<T>, Func<T,TResult> — giving one implementation that is type-safe for any T with zero boxing. Constraints (where T : class, new()) let the code assume capabilities of T.
Inside a catch block, bare throw rethrows preserving the original stack trace; throw ex resets the trace to the current line, destroying the evidence of where the failure started. Bare throw is almost always the right call — this is a deliberately laid trap question.
Yes — ordered most-specific first, and only the first match runs. Put FileNotFoundException before IOException before Exception; the compiler errors if an earlier catch would swallow a later one. Exception filters (catch (SqlException e) when (e.Number == 2601)) refine this further.
finally is a block that always runs when control leaves its try — deterministic cleanup. A finalizer is the GC-invoked ~ClassName() method — non-deterministic, may run seconds later or at shutdown. Same word root, completely different mechanisms.
Implicit typing: the compiler infers the variable's static type from the initialiser. It is still fully static — var is not dynamic — and it cannot be used without an initialiser. Use it when the type is obvious from the right-hand side.
A type whose member resolution is deferred to runtime via the DLR — typos compile and explode as RuntimeBinderException when hit. Legitimate uses are narrow: COM/Office interop, JSON of unknown shape, dynamic languages. Everywhere else, prefer static typing.
Compiler-generated immutable types from object initialisers — new { p.Name, p.Price } — used almost exclusively for intermediate LINQ projections. They don't cross method boundaries cleanly; when a shape needs a name, use a record.
Running multiple threads within one process, sharing its memory. In modern C# you rarely spawn raw Threads — the thread pool, Task.Run and Parallel handle scheduling — and the real interview substance is shared-state safety: lock, Interlocked, concurrent collections.
Compiler-rewritten asynchrony: an async method returning Task can await an operation, releasing the thread while the work (usually I/O) is in flight, and resuming when it completes. It is concurrency without thread-blocking, not automatic parallelism — and 'async all the way' beats .Result, which deadlocks UI and legacy ASP.NET contexts.
try around risky code, catch for typed handling, finally for cleanup, throw to raise or rethrow. Good practice: catch only what you can handle, keep exceptions exceptional (not control flow), and let the rest bubble to a global handler/middleware that logs once.
Your own classes derived from Exception — class PaymentDeclinedException : Exception — carrying domain-specific data so callers can catch precisely. Provide the standard constructors, including the inner-exception one; derive from Exception, not ApplicationException.
Language Integrated Query: a unified, composable query surface (Where, Select, GroupBy, Join) over anything enumerable or queryable — objects, EF Core, XML. Key interview point: deferred execution — a query runs when enumerated, not when written, and IQueryable translates the expression tree to SQL.
Converting an object graph to a persistable/transmittable format and back. The modern default is System.Text.Json; XML survives in enterprise integrations; the old BinaryFormatter is obsolete and a known security hole — saying so scores points.
Inspecting and invoking type metadata at runtime — typeof(T).GetProperties(), Activator.CreateInstance. It powers DI containers, serializers and test frameworks, at the cost of speed and compile-time safety; source generators are the modern compile-time alternative.
int? gives a value type a null state (HasValue/Value), with ??, ?. and pattern matching for handling. Since C# 8, nullable reference types make the compiler track possible nulls on strings and objects too — enable it and the warnings become a design tool.
System.Object. Every type — including value types, via boxing — inherits its members: ToString, Equals, GetHashCode, GetType, and the protected MemberwiseClone.
Two stages: the C# compiler (Roslyn) turns source into IL plus metadata inside an assembly; at runtime the CLR's JIT compiles each method's IL to native code on first call, with tiered compilation re-optimising hot paths. AOT publishing can move that second stage to build time.
So they are thread-safe, hashable (safe dictionary keys), internable and securely shareable — nobody can mutate a string out from under you. The cost is allocation on every 'modification', which is exactly the problem StringBuilder and Span<char> address.
Tuple<T1,T2> is a heap class with read-only Item1/Item2. ValueTuple — the (int Id, string Name) syntax — is a struct with named, mutable fields and no allocation, and is what modern C# means by 'returning a tuple'.
Lets the last parameter absorb a variable number of arguments as an array: void Log(params string[] lines) called as Log("a", "b", "c"). C# 13 extends it beyond arrays to spans and collection types.
.NET Framework (4.8) is the legacy Windows-only runtime, in maintenance mode. .NET Core was the cross-platform, open-source rewrite; from version 5 the two lines merged into just '.NET' (currently .NET 8/9, with LTS releases every two years). New work targets .NET; Framework is for maintaining old enterprise apps.
.NET's package manager: versioned libraries with dependency resolution, declared in the project file as PackageReference entries and restored from nuget.org or private feeds. It is how everything from JSON serializers to EF Core enters your build.
Dynamic Link Libraries — in .NET, assemblies containing compiled IL and metadata that other assemblies reference. A class library builds to a DLL; an executable project builds an EXE host plus its DLL. One assembly, many consumers, no code duplication.
Plain Old CLR Object — a class with no framework inheritance or attributes required, just properties and logic. EF Core entities are POCOs; the term signals persistence-ignorant, framework-agnostic domain models.
Data Transfer Object — a behaviour-free shape used to move data across a boundary (API response, service call), decoupling your wire contract from your domain entities so internals can change without breaking clients. C# records are the natural fit.
Single responsibility (one reason to change), Open/closed (extend without modifying), Liskov substitution (subtypes honour the base contract), Interface segregation (small, focused interfaces), Dependency inversion (depend on abstractions). Have one concrete example ready — DI in ASP.NET Core is the easiest D story.
Exactly one instance, globally reachable — in C# most cleanly a Lazy<T>-backed static, or better, a normal class registered as a singleton lifetime in the DI container. Be ready to discuss the downsides: hidden global state and harder testing.
Creation logic moved behind a method or dedicated type that returns an abstraction — callers ask for an IShipping and the factory decides which concrete class, hiding new and the selection rules. Factory Method uses subclassing for that decision; Abstract Factory groups related products into families.
Reading answers gets you through round one; writing code gets you hired. Krystyna Ślusarczyk's masterclass — the same instructor behind the original 70-question list — runs from C# basics through OOP, LINQ, async and clean-code practice with exercises after every section, which maps one-to-one onto sections 1–7 above. Watch a section, close the video, and answer the matching questions here from memory: that loop is the fastest prep cycle we know.
Two habits separate candidates who clear the technical round: narrating trade-offs (“I'd take readonly over const here because…”) instead of reciting definitions, and admitting the edges of your knowledge cleanly rather than improvising. Interviewers grade the second more generously than most candidates expect. And if the course budget is the blocker, Udemy's pricing floor comes around every few weeks — our next-sale tracker watches the calendar so you can time the purchase.
All of sections 1–3 (the first 33 questions) are fair game at the fresher level — classes, OOP pillars, value vs reference types, const vs readonly, string vs StringBuilder. Sections on async, LINQ internals and design patterns matter more from the 2–5 year mark.
Rounds usually open with 10–15 minutes of exactly these definitions before moving to a coding exercise. A crisp two-sentence answer with one example beats a memorised paragraph — which is how every answer on this page is written.
It is the course this guide pairs with: 4.7-rated on Udemy, taught by Krystyna Ślusarczyk, and it covers the exact ground these 70 questions test — OOP, LINQ, async, clean code — with exercises rather than slides. Through our link the coupon code CP260817G1 applies automatically at checkout.
Open the course through any button on this page — the code CP260817G1 is attached to the link, so Udemy shows the discounted price directly at checkout. If it has expired, the live codes on our Udemy coupons page are re-verified daily.
One walkthrough project you can narrate end-to-end, a data-structures refresher (arrays, dictionaries, hash sets — questions 36–39 and 59 here), and 2–3 LeetCode-easy problems in C# so syntax is automatic under pressure. Pattern questions (68–70) increasingly come with a “where would you NOT use this?” follow-up.
Zoutons may earn a commission when you enrol through links on this page, at no extra cost to you. Coupon code and course rating verified on August 25, 2026; Udemy prices and codes change frequently — the price at checkout is final. Questions adapted from the standard C# interview canon; all answers are Zoutons Editorial Team originals.