C# 12 --- Exhaustive Technical Interview Flashcards
How to use this deck This deck is ordered from language
fundamentals to implementation, trade-offs, production pitfalls, and finally 15-year-level architecture and war-story scenarios.
For senior interviews, do not stop at “what does this feature do?” Be ready to explain why you would use it, what it costs, what can go wrong, and how you would debug it.
1. C# and .NET Mental Model
Q: What is C#?
C# is a statically typed, object-oriented, general-purpose programming language created by Microsoft and commonly used with .NET.
C# provides language features such as classes, interfaces, generics, delegates, LINQ, async/await, pattern matching, records, nullable reference types, and modern memory-management features.
Q: Is C# the same thing as .NET?
Answer
No.
C# is the programming language.
.NET is the runtime, libraries, SDK, tooling, and application platform used to build and run applications written in C# and other languages.
Mnemonic
C# = language. .NET = platform. CLR = runtime.
Q: What is the CLR?
The Common Language Runtime is the execution environment for .NET applications.
It provides services such as managed memory, garbage collection, exception handling, type safety, threading, and JIT compilation.
Q: What happens when C# code runs?
C# source is compiled into Intermediate Language (IL) contained in an assembly such as a
.dllor.exe.At runtime, the .NET runtime executes the IL, using JIT compilation or other runtime compilation mechanisms to produce native machine code.
Q: What is an assembly?
An assembly is a compiled unit of .NET code, commonly a
.dllor.exe, containing IL, metadata, and other information required by the runtime.
Q: What is the difference between compile-time and runtime in C#?
Compile-time is when the compiler checks source code, resolves types, generates IL, and reports compile errors.
Runtime is when the application executes and runtime behavior such as dependency resolution, exceptions, JIT compilation, and garbage collection occurs.
2. Types, Variables, and Memory
Q: What is the difference between value types and reference types?
A value type variable directly represents its value. Examples include
int,double,bool,struct, andenum.A reference type variable holds a reference to an object. Examples include
class,string, arrays, and delegates.
Q: Does value type always mean stack and reference type always mean heap?
Answer
No.
That is an oversimplification. Value types can exist inside objects on the heap, inside arrays, or in other locations. Reference-type objects normally live on the managed heap, while the reference itself can be stored in different locations.
Common Pitfall
Never answer “struct = stack, class = heap” as a universal rule.
Q: What is boxing?
Boxing converts a value type into an
objector compatible interface reference by wrapping the value in an object on the managed heap.Example:
int x = 10; object o = x;
Q: What is unboxing?
Answer
Unboxing explicitly extracts the value type from a boxed object.
Example:
int x = (int)o;Performance Pitfall
Boxing can create allocations and GC pressure in hot paths. Generic APIs often avoid boxing by preserving the value type.
Q: Why is
stringa reference type but behaves like an immutable value?
stringis a reference type, but its contents cannot be changed after creation.Operations that appear to modify a string actually create another string.
Q: Why is string immutability useful?
It makes strings safer to share, simplifies reasoning about them, and supports runtime optimizations such as string interning.
Q: What is string interning?
String interning allows identical string literals to share a single interned instance.
This can reduce duplicate storage for repeated strings, although developers should not rely on interning as a general-purpose caching strategy.
Q: What is
constin C#?
constdefines a compile-time constant. Its value must be known at compile time and is implicitly static.Example:
public const int MaxRetries = 3;
Q: What is
readonly?A
readonlyfield can be assigned during declaration or in a constructor and cannot normally be reassigned afterward.
Q:
constvsreadonly?Answer
constis compile-time and implicitly static.
readonlyis runtime-initialized and can be instance-specific.Use
constfor values that are genuinely compile-time constants. Usereadonlywhen the value is determined during construction or startup.Versioning Pitfall
Public
constvalues can be inlined into consuming assemblies. Changing a public constant may require consumers to be recompiled to observe the new value.A
static readonlyfield avoids that particular compile-time substitution behavior.
Q: When should a field be
readonly?Use
readonlywhen the field represents state that should be assigned during initialization/construction but should not change during the object’s lifetime.
3. Classes, Objects, and Encapsulation
Q: What is encapsulation?
Encapsulation means keeping an object’s state and invariants under the control of the object rather than allowing arbitrary external mutation.
Q: Why prefer behavior over public mutable fields?
Public mutable state allows callers to violate invariants.
Encapsulating state behind methods or controlled properties lets the class enforce valid transitions.
Q: What is the difference between a field and a property?
A field directly stores data.
A property provides an abstraction around access to data and can contain getters, setters, validation, or computed behavior.
Q: What is an auto-property?
An auto-property lets the compiler generate the backing field.
Example:
public string Name { get; set; }
Q: What is an init-only property?
An
initaccessor allows a property to be assigned during object initialization but prevents normal assignment afterward.Example:
public string Name { get; init; }
Q:
initvsreadonly?
readonlyapplies to fields.
initapplies to properties and allows assignment during object initialization.
Q: What is a static member?
Answer
A static member belongs to the type rather than an individual object instance.
Design Pitfall
Static state is effectively shared state. It can complicate testing, concurrency, lifecycle management, and multi-tenant behavior.
Q: What is a sealed class?
A sealed class cannot be inherited.
It is useful when inheritance would violate the design or when the type is intentionally closed for extension.
Q: What is an abstract class?
An abstract class cannot be instantiated directly and can provide shared state or implementation for derived classes.
Q: Abstract class vs interface?
An abstract class is useful for a common base abstraction with shared implementation/state.
An interface defines a contract and allows a class to implement multiple interfaces.
Prefer interfaces for capabilities and boundaries; use abstract classes when shared implementation or state genuinely belongs in a common base.
Q: Can an interface contain implementation?
Yes. Modern C# interfaces can contain default implementations and other members, although interfaces should still primarily represent contracts.
4. Inheritance, Polymorphism, and Dispatch
Q: What is polymorphism?
Polymorphism allows code to work through an abstraction while the actual runtime type determines behavior.
Q: What is method overloading?
Multiple methods have the same name but different parameter signatures.
Overload resolution primarily happens at compile time.
Q: What is method overriding?
A derived class provides a new implementation for a virtual or abstract member defined by the base class.
Runtime dispatch chooses the appropriate override.
Q:
virtualvsoverride?
virtualallows a derived class to replace a member.
overridesupplies that replacement implementation.
Q: What does
newmean when used on an inherited member?Answer
It hides the inherited member rather than overriding it.
The member selected can therefore depend on the compile-time reference type.
Common Pitfall
newis not polymorphic overriding. Useoverridewhen you intend runtime polymorphism.
5. Interfaces and Generics
Q: Why use generics?
Generics provide type-safe reusable code without requiring casts and can avoid boxing for value types.
Q: What are generic constraints?
Constraints restrict the types that can be used as generic arguments.
Examples include
where T : class,struct,new(), a base class, or an interface.
Q: Why are generic constraints useful?
They let the compiler guarantee capabilities required by the generic algorithm and allow clearer APIs.
Q: What is covariance?
Covariance allows a more-derived type to be used where a less-derived type is expected for certain output-only generic abstractions.
Example:
IEnumerable<Dog>can be assigned toIEnumerable<Animal>.
Q: What is contravariance?
Answer
Contravariance allows a less-derived type to be used where a more-derived type is expected for certain input-only generic abstractions.
Example: a consumer of
Animalcan often be used where a consumer ofDogis expected.Mnemonic
Covariance = output
Contravariance = input
6. Delegates, Events, and Lambdas
Q: What is a delegate?
A delegate is a type-safe representation of a method reference.
Delegates enable callbacks, strategies, events, and functional-style APIs.
Q:
Func<>vsAction<>?
Func<>represents a delegate that returns a value.
Action<>represents a delegate that returnsvoid.
Q: What is a lambda expression?
A lambda is an inline function expression, commonly used with delegates and LINQ.
Example:
x => x.Price > 100
Q: What is an event?
Answer
An event provides a controlled publisher/subscriber mechanism built on delegates.
Consumers can subscribe and unsubscribe, while the declaring type controls event invocation.
Design Pitfall
Long-lived publishers retaining subscribers can keep objects alive longer than intended. Event subscriptions can therefore contribute to memory leaks in certain object-lifecycle designs.
7. Records, Structs, and Immutability
Q: What is a record?
A record is a type designed to model data with value-oriented equality and concise immutable-style construction.
Records can be classes or structs.
Q: Record vs class?
A typical class uses reference identity unless equality is explicitly implemented.
A record is designed around value-based equality and data-centric modeling.
Q: When would you use a record for an API DTO?
Records are a good fit when the DTO represents data rather than behavior and value-based equality or immutability is desirable.
Q: What is a
record struct?It is a value-type record providing record-style value equality and concise data modeling.
Q: Struct vs class?
Answer
Use a struct for small, value-like data where value semantics are appropriate.
Use a class for entities, polymorphic objects, larger mutable state, or objects whose identity matters.
Performance Pitfall
Making a large mutable struct can be expensive because copying a value type copies its contents. Structs should generally remain small and conceptually value-like.
8. Nullable Reference Types
Q: What are nullable reference types?
Nullable reference types are a compiler analysis feature that lets developers express whether a reference is expected to be null.
Example:
stringmeans non-null intent.
string?means null is permitted.
Q: Do nullable reference types change the CLR representation?
No. They primarily provide compile-time analysis and warnings. They do not turn
stringinto a fundamentally different runtime type.
Q: What does the null-forgiving operator
!do?Answer
It tells the compiler that the developer believes an expression is non-null.
It does not perform a runtime null check.
Common Pitfall
customer!.Namecan still throwNullReferenceException. The!suppresses a compiler warning; it does not make the object non-null.
Q: What does `?
?` do? It returns the left operand if it is not null; otherwise it returns the right operand.
Q: What does `?
?=` do? It assigns the right-hand value only when the left-hand variable is null.
Q: What does `?
.` do? It performs null-conditional access and returns null instead of dereferencing a null receiver.
9. Pattern Matching
Q: What is pattern matching in C#?
Pattern matching lets code test and extract information from values using patterns.
It supports type, property, relational, logical, positional, and list patterns.
Q: Why is pattern matching useful in production code?
It can make branching logic more explicit and reduce nested casts and conditionals.
Q: What are relational patterns?
They allow conditions such as
>,<,>=, and<=inside patterns.
Q: What are property patterns?
They match objects based on property values.
Example:
order is { Status: OrderStatus.Paid, Total: > 100 }
Q: What are list patterns in C# 12?
List patterns allow matching array/list-like sequences using patterns such as
[1, 2, 3]and slice patterns such as[.., 3].
10. Exceptions
Q: What is an exception?
An exception represents an abnormal condition that interrupts normal control flow and can propagate up the call stack until handled.
Q: When should you use exceptions?
Use exceptions for exceptional failures rather than ordinary expected branching.
For expected outcomes such as “customer not found” or validation failures, explicit result types or domain responses may be clearer depending on the API.
Q:
throwvsthrow ex?Answer
throw;rethrows the current exception while preserving the original stack trace.
throw ex;resets the stack-trace context at the rethrow point.Critical Pitfall
Prefer
throw;when rethrowing an exception you caught.
Q: What is exception wrapping?
Exception wrapping throws a new exception while preserving the original exception as an inner exception.
It is useful when adding domain or infrastructure context.
Q: Should you catch
Exceptioneverywhere?Answer
No.
Catch exceptions where you can meaningfully handle, translate, recover, or add context. Application boundaries can catch broad exceptions for logging and consistent error responses when appropriate.
Production Pitfall
Catching an exception, logging it, and continuing silently can turn a clear failure into corrupted or inconsistent state.
11. Collections
Q:
List<T>vsHashSet<T>?
List<T>preserves insertion order and provides indexed access.
HashSet<T>is optimized for uniqueness and fast membership checks.
Q:
Dictionary<TKey,TValue>vsConcurrentDictionary<TKey,TValue>?
Dictionaryis not designed for concurrent mutation.
ConcurrentDictionaryprovides thread-safe operations for supported concurrent access patterns.
Q:
IEnumerable<T>vsICollection<T>vsIList<T>?
IEnumerable<T>primarily represents enumeration.
ICollection<T>adds collection semantics such as count and mutation.
IList<T>adds index-based access.
Q: Why should APIs often return abstractions rather than concrete collections?
Returning an appropriate abstraction communicates what callers are allowed to rely on and reduces coupling to the concrete implementation.
12. LINQ
Q: What is LINQ?
Language Integrated Query provides a consistent query syntax and API for working with in-memory collections and other query providers.
Q: What is deferred execution?
Many LINQ operators do not execute immediately. They create a query that runs when enumerated.
Q: What is the difference between
IEnumerable<T>andIQueryable<T>in LINQ?Answer
IEnumerable<T>generally executes operations in .NET memory.
IQueryable<T>represents an expression tree that a provider, such as EF Core, can translate to another query language such as SQL.Critical Pitfall
Calling
ToList()too early can pull a large dataset into memory and move filtering from the database to the application.
Q:
SelectvsWhere?
Wherefilters elements.
Selectprojects each element into another shape.
Q:
FirstvsFirstOrDefault?
Firstthrows if no element exists.
FirstOrDefaultreturns the default value when no element exists.
Q:
SinglevsFirst?
Singleexpects exactly one matching element and throws if there are zero or multiple matches.
Firstonly requires at least one and returns the first match.
Q: Why can multiple LINQ enumerations be dangerous?
Answer
A deferred query may execute its underlying work each time it is enumerated.
With database queries, this can result in multiple SQL executions; with expensive in-memory operations, it can repeat computation.
Performance Mnemonic
Query once when appropriate → materialize once → reuse.
13. C# 12 Features
Q: What are primary constructors in C# 12?
Primary constructors allow constructor parameters to be declared directly on the type declaration.
They reduce boilerplate and can be used by classes and structs.
Q: Are primary constructor parameters automatically fields?
Answer
No.
They are parameters in scope throughout the type. The compiler creates storage only when needed by the implementation.
Common Pitfall
Do not describe primary constructor parameters as automatically becoming public properties or fields.
Q: What are collection expressions in C# 12?
Collection expressions use
[...]to create collection-like values.Examples include
[1, 2, 3]and[ ..existingItems, 4 ].
Q: What is the spread operator in C# 12 collection expressions?
..spreads elements from another collection or compatible sequence into a collection expression.
Q: What are interceptors in C# 12?
Interceptors are an advanced compiler feature intended primarily for source generators and framework/tooling scenarios. They are not a general replacement for runtime middleware or dependency injection.
14. Async/Await
Q: What does
asyncdo?
asyncenables use ofawaitwithin a method and allows the compiler to transform asynchronous control flow.It does not automatically create a new thread.
Q: What does
awaitdo?Answer
awaitasynchronously waits for a task-like operation to complete and allows the method to yield control rather than synchronously blocking the thread.Critical Mnemonic
Async does not mean “new thread.”
Async primarily means don’t block while waiting.
Q:
TaskvsThread?A thread is an execution resource.
A
Taskrepresents an asynchronous operation and may use thread-pool threads, I/O completion mechanisms, or other scheduling mechanisms depending on the operation.
Q: What is the thread pool?
The .NET thread pool maintains reusable worker threads for application work, reducing the cost of creating dedicated threads.
Q: What is thread-pool starvation?
Answer
Thread-pool starvation occurs when available worker threads are occupied or blocked, preventing queued work from getting threads promptly.
Synchronous blocking on asynchronous operations is a common contributor.
Production Pitfall
Avoid patterns such as
.Resultor.Wait()on asynchronous operations in server code when an async path is available.
Q: Why should ASP.NET Core code generally be async all the way down?
Asynchronous I/O allows request threads to be returned to the pool while waiting for databases, HTTP services, or other I/O operations.
This improves scalability under concurrent load.
Q: What is
Task.WhenAll?It creates a task that completes when all supplied tasks complete.
It is useful when independent asynchronous operations can run concurrently.
Q: When should you not use
Task.WhenAll?Do not parallelize operations that have ordering or dependency requirements, or launch unbounded numbers of tasks that can overwhelm downstream systems.
Q: What is
CancellationToken?Answer
It provides cooperative cancellation.
Code observes the token and stops work when cancellation is requested.
Production Tip
Cancellation is cooperative, not forcibly aborting a thread. Propagate cancellation tokens through I/O boundaries whenever practical.
15. Memory Management and GC
Q: What is garbage collection in .NET?
The GC automatically identifies unreachable managed objects and reclaims their memory.
Q: What are GC generations?
The generational GC groups managed objects into generations based on age:
- Gen 0
- Gen 1
- Gen 2
Short-lived objects are generally collected more frequently.
Q: Why can excessive allocations hurt a high-throughput service?
Allocations increase GC work and memory pressure. Frequent allocation of short-lived objects can increase collection frequency and CPU overhead.
Q: What is
IDisposable?
IDisposableprovides a deterministic cleanup pattern for resources that need explicit release, such as unmanaged handles or certain managed wrappers around external resources.
Q: Does
Dispose()free managed memory?Not directly. Garbage collection handles managed memory.
Dispose()releases resources that require deterministic cleanup.
Q: What does
usingdo?
usingensuresDispose()is called when execution leaves the relevant scope, including when an exception occurs.
Q: What is
IAsyncDisposable?It provides asynchronous cleanup through
DisposeAsync(), useful when resource disposal itself requires asynchronous I/O.
Q: What is a memory leak in a garbage-collected application?
It usually means objects remain reachable even though the application no longer logically needs them.
Common causes include long-lived caches, static references, event subscriptions, and accidentally retained object graphs.
16. Thread Safety and Concurrency
Q: What is a race condition?
A race condition occurs when correctness depends on timing or interleaving between concurrent operations.
Q: What is a lock?
Answer
lockprovides mutual exclusion so only one thread at a time can enter the protected critical section for a given lock object.Common Pitfall
Do not lock on publicly accessible objects or strings. Prefer a private dedicated lock object when using
lock.
Q: What is
Interlocked?
Interlockedprovides atomic operations such as increment, exchange, and compare-and-swap for certain shared values.
Q:
lockvsInterlocked?
Interlockedis useful for small atomic state transitions.
lockis appropriate when multiple operations must be protected as one critical section.
Q: What is a deadlock?
A deadlock occurs when concurrent operations wait indefinitely for resources held by each other.
Q: How can deadlocks be prevented?
Establish consistent lock ordering, minimize lock scope, avoid unnecessary nested locks, and prefer higher-level concurrency primitives where appropriate.
Q: Is
ConcurrentDictionarya replacement for every lock?No.
It provides thread-safe dictionary operations, but compound business operations may still require synchronization or atomic APIs.
17. Reflection, Attributes, and Source Generation
Q: What is reflection?
Reflection allows code to inspect metadata and types at runtime and can dynamically access members.
Q: What are attributes?
Attributes attach metadata to code elements such as classes, properties, methods, and parameters.
Q: When can reflection become a performance or architecture problem?
Answer
Heavy reflection in hot paths can increase startup and runtime overhead and make code harder to analyze statically.
Modern .NET Tip
Source generation can move some work from runtime reflection to compile time, improving startup, trimming compatibility, or performance for suitable scenarios.
18. Dependency Injection and Design
Q: What is dependency injection?
Dependency injection means a class receives dependencies from an external composition mechanism rather than constructing them itself.
Q: Why is constructor injection usually preferred?
It makes dependencies explicit, supports immutability, and makes invalid object construction harder.
Q: What is the service locator anti-pattern?
Service locator hides dependencies behind a generic service lookup instead of declaring them explicitly.
This makes dependencies harder to discover and test.
Q: Interface vs abstract class in dependency injection?
Interfaces are often preferable at application boundaries because they define contracts without imposing inheritance.
Abstract classes can be appropriate when shared implementation is genuinely required.
19. Production Code Quality
Q: How do you decide whether a method should be async?
If it performs asynchronous I/O and the underlying API supports async, propagate the async model rather than blocking synchronously.
CPU-bound work is a different problem and may require different parallelism decisions.
Q: When should you use
Span<T>?
Span<T>is useful for high-performance synchronous memory processing without unnecessary allocations or copying.
Q: What is
ReadOnlySpan<T>?Answer
It provides a read-only view over contiguous memory without requiring a new allocation.
Common Pitfall
Span<T>is stack-only/ref-struct-based and cannot be freely stored on the heap, captured by lambdas, or used across asynchronous suspension points.
Q: What is
Memory<T>?
Memory<T>provides a memory abstraction that can be stored and used in asynchronous scenarios whereSpan<T>cannot.
20. C# Architecture Scenarios
Q: You inherit a C# service with huge methods, static state, and direct database calls. How would you improve it?
Answer
First identify behavior and dependencies before refactoring.
I would introduce boundaries around business logic, isolate persistence, remove unnecessary global state, introduce dependency injection, add characterization tests, and refactor incrementally rather than rewriting everything.
Architect Tip
In production, safe incremental change beats elegant rewrites unless there is a compelling reason for a rewrite.
Q: A C# API has high CPU and high allocation rates. What would you investigate?
Profile before changing code.
Investigate allocation hot spots, serialization, LINQ materialization, string processing, boxing, excessive temporary objects, logging, JSON payload size, and algorithmic complexity.
Q: An API has low CPU but poor latency. What would you investigate?
Look for I/O waits:
- Database
- HTTP calls
- Network
- Lock contention
- Thread-pool starvation
- External service latency
- Connection-pool exhaustion
Q: An API occasionally throws
ObjectDisposedException. How would you investigate?Identify the disposed object and ownership boundary.
Check service lifetimes,
usingscopes, async lifetime gaps, shared disposable instances, and whether an object is being used after its owning scope has ended.
21. C# War Stories
Q: Tell me about a C# performance problem you diagnosed. Structure the answer: Symptom → measurement → hypothesis → profiling evidence → fix → regression prevention. Include concrete metrics where possible.
Q: Tell me about a concurrency bug you fixed. Explain the shared state, race condition, observable failure, synchronization strategy, and why the fix preserved throughput.
Q: Tell me about a production memory problem in .NET. Explain how you distinguished a true memory-retention problem from normal GC behavior, what diagnostics you used, and what object graph or allocation pattern caused the issue.
Q: Tell me about a time you rejected a clever C# feature. Explain why readability, maintainability, debugging, performance, or team familiarity outweighed the feature's elegance.
Answer
Senior Interview Tip
Strong architects demonstrate restraint. Knowing a language feature does not mean every codebase should use it.
22. Senior Follow-up Traps
Q: You said async improves performance. Does it always make code faster?
No.
Async primarily improves scalability for waiting-heavy workloads by avoiding blocked threads. It does not automatically reduce the intrinsic duration of the underlying operation.
Q: You said structs are faster than classes. Is that always true?
No.
Structs can avoid object allocations in some scenarios, but copying large structs can be expensive and value semantics can introduce other costs.
Q: You said
readonlymakes an object immutable. Is that true?No.
readonlyprevents reassignment of the field reference/value. If the field references a mutable object, the object’s internal state can still change.
Q: You said
IEnumerablemeans lazy. Is that always true?No.
IEnumerable<T>represents enumeration. The underlying implementation may be eager or lazy.
Q: You said
Task.Runmakes an operation asynchronous. Is that always appropriate?No.
Task.Runschedules work on the thread pool. It is generally not the solution for naturally asynchronous I/O.
Q: You said nullable reference types prevent null exceptions. Is that true?
Answer
No.
They provide compiler analysis and warnings. Runtime nulls can still occur.
Tip
Final C# Interview Mental Model For senior C# questions, reason in this order:
Type semantics → memory → concurrency → async → performance → API design → failure mode → maintainability.