In this article
Types and memory
What is the difference between value types and reference types in C#?
A variable of a value type contains the instance itself, while a variable of a reference type contains a reference to an instance. By default, assignment, passing an argument and returning a result all copy the variable's value, so copying a value-type variable copies the data and copying a reference copies only the pointer (value types reference, updated March 2026).
Why it is asked: a frequent source of unexpected sharing bugs. For the wider picture see coding interview preparation. Read the full explanation: Core platform interview questions.
When would you choose a struct over a class?
Choose a struct for small data that should behave like a value, and a class when objects need identity and shared state. Microsoft's guidance is to define and use immutable value types, since mutable ones are error-prone: copying a struct that holds a reference-type field copies only the reference, so the copy and the original still share that object (value types reference).
Why it is asked: it tests judgment about copy cost and mutation. Read the full explanation: Core platform interview questions.
What does it mean that everything derives from object?
In C#'s unified type system, all types, reference types and value types, predefined and user-defined, inherit directly or indirectly from System.Object, so a value of any type except ref struct can be assigned to an object variable. Converting a value type to object boxes it, and converting back unboxes it (built-in reference types).
Why it is asked: it links the type system to boxing. Read the full explanation: Core platform interview questions.
What are boxing and unboxing, and why do they matter?
Boxing converts a value type to object or to an interface it implements: the runtime allocates an object on the managed heap and copies the value into it. Unboxing is the explicit conversion back. Microsoft calls both computationally expensive compared with simple assignment, and unboxing to the wrong type throws an InvalidCastException (boxing and unboxing).
Why it is asked: a classic hidden cost in loops over object collections. Read the full explanation: Core platform interview questions.
Can a string change, and does == compare references?
A string cannot change after it is created (System.String, July 2025); code that appears to modify one makes a new string object and the old one becomes eligible for garbage collection. Although string is a reference type, == and != compare the characters, so two separate strings with the same content are equal while object.ReferenceEquals returns false (built-in reference types). The trap: if both operands are typed object, == is reference equality, so use string.Equals. String.Intern returns the same reference for equal strings (String.Intern, July 2025).
Why it is asked: it separates value equality from reference identity. Read the full explanation: Core platform interview questions.
What is the difference between const and readonly?
A const field is a compile-time constant and can only be initialised at its declaration. A readonly field can be assigned in its declaration or in any constructor of the same class, so it can hold run-time values and differ between instances. A readonly reference still lets you change the object it points to (readonly keyword).
Why it is asked: the last point trips up candidates. Read the full explanation: readonly keyword.
What is a record, and how does it differ from a class?
A record is a type with built-in support for value equality, non-destructive copying with a with expression, and readable ToString output. A record (or record class) is a reference type and a record struct is a value type. Two records are equal when they are the same type and store the same values; two ordinary class instances are equal only if they are the same object (records reference, updated June 2026).
Why it is asked: it tests modern C# knowledge. Read the full explanation: records reference.
Memory management and resources
How does the .NET garbage collector work?
The garbage collector (GC) is the runtime's automatic memory manager: it frees managed objects that the application's roots can no longer reach. It divides the managed heap into three generations, 0, 1 and 2; new objects start in generation 0, except objects of 85,000 bytes or more, which go to the large object heap, and survivors are promoted. Collecting a younger generation is faster than collecting everything (garbage collection fundamentals, October 2025).
Why it is asked: it shows whether you understand memory behind the language. Read the full explanation: Core platform interview questions.
Does the garbage collector clean up files and connections?
Not deterministically. The garbage collector manages only memory; unmanaged resources such as file handles, window handles and network connections need explicit cleanup, which it does not know how to do. Dispose releases the handle when the caller says so, and a SafeHandle or finalizer is only a backstop that runs at an unpredictable time if Dispose is never called. So call Dispose, usually through using; Microsoft recommends a public Dispose method and says to call it when you use an object that wraps one (garbage collection fundamentals).
Why it is asked: leaked handles are a common production fault. Read the full explanation: Core platform interview questions.
How do IDisposable and the using statement work together?
IDisposable.Dispose releases resources deterministically, when the caller says so rather than when the collector runs. When control leaves the block of a using statement, the disposable instance is disposed, even if an exception occurs inside the block (using statement, January 2026). Microsoft says Dispose should be safe to call more than once (implementing Dispose).
Why it is asked: it tests resource discipline. Read the full explanation: Core platform interview questions.
When do you need a finalizer, and what is a SafeHandle?
A finalizer is only required if your class directly references unmanaged resources, which Microsoft calls a highly advanced scenario that can typically be avoided. The recommended alternative is to wrap the unmanaged handle in a SafeHandle, which supplies the finalizer for you. Calling GC.SuppressFinalize from Dispose tells the collector the finalizer need not run (implementing Dispose).
Why it is asked: it separates a memorised pattern from understanding. Read the full explanation: Core platform interview questions.
Knowing it is half the job. Saying it is the other half.
Interview Clozo is an AI interview copilot for real interview rounds: it hears the question and puts a strong answer on your screen, and you say it in your own words. See the features or how it works.
Start Free Trial →Objects and interfaces
What is the difference between an interface and an abstract class?
An interface defines a contract of methods, properties, events and indexers, and a type can implement many of them; a class can inherit from only one base class. Microsoft says to use an abstract class when related types share state, constructors or non-public members, and an interface for a contract that cuts across unrelated hierarchies (interfaces guide, April 2026).
Why it is asked: it is the standard design question for object-oriented languages. Read the full explanation: interfaces guide; the same question in Java is covered in Java object-oriented interview questions.
What is a delegate, and how do events relate to it?
A delegate is a built-in reference type that encapsulates a named or anonymous method; it is like a function pointer in C++ but type-safe. The generic Action and Func types cover most needs, so you rarely define a custom delegate type (built-in reference types). An event builds on a delegate: it is a delegate-typed member that other classes can only subscribe to with += or unsubscribe from with -=, while the declaring class decides when it is raised (events, March 2025).
Why it is asked: callbacks and events appear in most real code. Read the full explanation: delegates and events on Microsoft Learn.
Async and threads
Does async and await create new threads?
No. The async and await keywords do not create extra threads, because an async method does not run on its own thread. An await expression does not block the current thread while the awaited task runs; it signs up the rest of the method as a continuation and returns control to the caller (task asynchronous programming model).
Why it is asked: it is a frequent async misconception. Read the full explanation: concurrency interview questions.
What should an async method return, and what is wrong with async void?
Return Task<TResult> if the method returns a value and Task if it does not. async void is meant for event handlers only: the documentation says it cannot be awaited and its caller cannot catch any exception it throws. By convention, names of methods that return awaitable types end in Async (task asynchronous programming model).
Why it is asked: unhandled exceptions in async void are a known trap. Read the full explanation: concurrency interview questions.
When should you use Task.Run?
Use Task.Run to move processor-bound work to a background thread. The documentation says a background thread does not help a process that is only waiting for results, such as web or file input and output, where async methods alone suffice. It adds that async with Task.Run is preferable to BackgroundWorker for processor-bound work (task asynchronous programming model).
Why it is asked: it separates waiting from computing. Read the full explanation: concurrency interview questions.
How does the lock statement work, and what should you lock on?
lock acquires a mutual-exclusion lock on an object, runs its block, and releases the lock even if an exception occurs, so at most one thread runs the body at a time. Microsoft says to lock a dedicated System.Threading.Lock instance from C# 13 (runtime version 9), and to avoid this, a Type or a string. You cannot use await inside the block (lock statement, January 2026).
Why it is asked: it tests safe sharing between threads. Read the full explanation: concurrency interview questions.
LINQ
What is deferred execution in LINQ?
Deferred execution means a LINQ query runs when you enumerate it, for example in a foreach, not where you declare it; LINQ is a C# model for querying objects, databases and other sources with one syntax. The query variable stores the instructions, not the data, so enumerating it twice can give different results if the source changed (introduction to LINQ queries, April 2024).
Why it is asked: it explains many surprising results. Read the full explanation: Core platform interview questions.
What is the difference between IEnumerable and IQueryable?
The difference is where the query runs: with IEnumerable<T> the filtering happens in memory in your process, while IQueryable<T> carries an expression tree that a provider translates and runs at the source, for example as SQL (IQueryable interface, July 2025). IQueryable<T> derives from IEnumerable<T>, so a database table counts as a LINQ data source and its results can be enumerated (introduction to LINQ queries). The pitfall: once you call AsEnumerable or ToList, the rest of the query runs in memory, so put filters before it.
Why it is asked: it tests whether you know where a query actually runs. Read the full explanation: Core platform interview questions.
Which LINQ operators run immediately, and how do you force a query to run?
Operators that return a single value, such as Count, Max, Average and First, execute immediately. Calling ToList or ToArray forces any query to run and caches its results in a collection, so later enumerations reuse them instead of fetching again. Operators that return a sequence, such as Where and Select, use deferred execution (introduction to LINQ queries).
Why it is asked: it prevents repeated database calls. Read the full explanation: Core platform interview questions.
What is the difference between streaming and nonstreaming LINQ operators?
A streaming operator, such as Where or Select, processes each source element as it is read and yields results without reading everything first. A nonstreaming operator, such as OrderBy or GroupBy, must read all the source data before it can yield a result. Both are deferred, but nonstreaming operators hold the whole source in memory (introduction to LINQ queries).
Why it is asked: it matters for large data sets. Read the full explanation: Core platform interview questions.
Follow-up questions
What happens if you lock on this?
Microsoft advises avoiding this, a Type or a string as the lock object, because code outside your class can take the same lock; lock a private dedicated object, or a System.Threading.Lock instance from C# 13 (runtime version 9) (lock statement, January 2026). Related questions are on the concurrency interview questions page.
Why can't you await inside a lock?
The lock statement does not allow an await expression inside its block (lock statement, January 2026). An await can suspend the method and resume it on a different thread, so the lock would stay held across that switch while other code waits for it, which risks deadlock (async errors reference, March 2026). Also, lock uses Monitor, which only the acquiring thread may release (synchronization primitives, October 2018). Use a SemaphoreSlim, which has no thread affinity, to wait asynchronously.
Why does modifying a struct inside a list not change the list?
A struct is a value type, so reading it out of the list copies the data, and changing the copy leaves the stored element untouched (value types reference, March 2026). Replace the element, or use a class when you need shared, mutable state. How the rounds of a loop fit together is in interview loops.
- Value-type variables hold the data and are copied on assignment; reference-type variables hold a reference.
- Boxing allocates on the heap and costs more than assignment; unboxing to the wrong type throws.
- The garbage collector frees managed memory only; release files and connections with
Dispose. asyncandawaitdo not create threads; useTask.Runonly for processor-bound work.- A LINQ query runs when enumerated;
ToListorToArrayforces it and caches the result.
Sources
- Value types (C# reference) — Microsoft Learn, 20 Mar 2026
- Built-in reference types (C# reference) — Microsoft Learn, 14 Jan 2026
- Boxing and Unboxing (C# programming guide) — Microsoft Learn, 13 Oct 2025
- readonly keyword (C# reference) — Microsoft Learn, 22 Jan 2026
- Records (C# reference) — Microsoft Learn, 5 Jun 2026
- Fundamentals of garbage collection (.NET) — Microsoft Learn, 22 Oct 2025
- Implement a Dispose method (.NET) — Microsoft Learn, 22 Oct 2025
- Interfaces: define behavior for multiple types (C#) — Microsoft Learn, 10 Apr 2026
- The Task Asynchronous Programming (TAP) model with async and await (C#) — Microsoft Learn, 13 Oct 2025
- The lock statement (C# reference) — Microsoft Learn, 16 Jan 2026
- The using statement (C# reference) — Microsoft Learn, 16 Jan 2026
- Events (C# programming guide) — Microsoft Learn, 11 Mar 2025
- String class (System) — Microsoft Learn, 1 Jul 2025
- String.Intern method (System) — Microsoft Learn, 1 Jul 2025
- IQueryable<T> interface (System.Linq) — Microsoft Learn, 1 Jul 2025
- Resolve errors and warnings in async methods that use the await operator (C# reference) — Microsoft Learn, 16 Mar 2026
- Overview of synchronization primitives (.NET) — Microsoft Learn, 1 Oct 2018
- Introduction to LINQ Queries (C#) — Microsoft Learn, 22 Apr 2024