HireHireInterview Quizzes › .NET Developer

.NET Developer Interview Questions

Think you're ready? These are the questions that actually decide .NET Developer interviews. Warm up on Easy — then face the Hard round, where 95% of candidates crumble. 79 questions across 3 levels, instant score, completely free.

79Questions
3Difficulty levels
95%Fail the hard round
FreeInstant score
Easy
Warm-up · 20 Qs
Medium
Practical · 29 Qs
Hard
Brutal · 30 Qs
⚡ Take the .NET Developer quiz — get your score →

The .NET Developer interview questions

Below are the real questions, grouped by difficulty. Expand any one to reveal the correct answer and why — or take the timed quiz for a score you can share. Can you clear the Hard round?

Easy round 20 questions

You pass an int into a method, modify it inside, but the caller's variable is unchanged afterward. Why?
  • A. int is a reference type
  • B. int is a value type passed by value, so the method gets a copy ✓
  • C. It is due to garbage collection
  • D. int is an immutable reference
Correct answer: B. Value types like int are copied when passed by value, so changes inside the method don't affect the caller.
You call s.ToUpper() on a string but never assign the result to anything. What is the effect on s?
  • A. s is modified in place to uppercase
  • B. s stays unchanged because strings are immutable ✓
  • C. It causes a compilation error
  • D. It throws a runtime exception
Correct answer: B. Strings are immutable, so string methods return a new string and leave the original untouched.
You wrap a FileStream in a using block. What does that guarantee?
  • A. Dispose() is called even if an exception is thrown ✓
  • B. The file is deleted afterward
  • C. The stream is cached globally
  • D. Garbage collection runs immediately
Correct answer: A. A using block compiles to try/finally that calls Dispose() no matter how the block exits.
You call an async method but do not await it. What happens?
  • A. It causes a compile error
  • B. It runs fully synchronously
  • C. The method starts running but the caller does not wait for it to finish ✓
  • D. The returned task never starts
Correct answer: C. Without awaiting, execution continues past the call while the returned task runs independently.
You build a LINQ query using Where() but never enumerate it. When does the filtering actually execute?
  • A. Immediately when Where is called
  • B. At compile time
  • C. It never runs at all
  • D. Not until the query is enumerated, e.g. via foreach or ToList() ✓
Correct answer: D. LINQ uses deferred execution; the query runs only when it is iterated.
Calling .Length on a string variable whose value is null throws which exception?
  • A. NullReferenceException ✓
  • B. ArgumentNullException
  • C. IndexOutOfRangeException
  • D. InvalidOperationException
Correct answer: A. Accessing a member on a null reference raises a NullReferenceException.
In C#, comparing two string variables with the == operator compares what?
  • A. Only their references
  • B. Their character values, because == is overloaded for string ✓
  • C. Their raw memory addresses
  • D. Only their hash codes
Correct answer: B. The == operator is overloaded for string to compare the actual character sequences.
You need a collection that grows dynamically as items are added at runtime. Which fits best?
  • A. A fixed-size int[] array
  • B. A const array
  • C. List<T> ✓
  • D. A string literal
Correct answer: C. List<T> resizes automatically as elements are added, unlike a fixed-length array.
Code placed in a finally block executes under which condition?
  • A. Whether or not an exception was thrown in the try ✓
  • B. Only if an exception occurs
  • C. Only if no exception occurs
  • D. Only when a return statement is reached
Correct answer: A. A finally block always runs after the try, regardless of whether an exception was thrown.
A class member marked private is accessible from where?
  • A. Any class in the same assembly
  • B. Derived classes only
  • C. Anywhere in the program
  • D. Only within the same class ✓
Correct answer: D. private restricts access to the declaring class itself.
A class implements the IComparable interface. What must it therefore provide?
  • A. A CompareTo method implementation ✓
  • B. A parameterless constructor
  • C. A static Main method
  • D. A finalizer
Correct answer: A. Implementing IComparable requires providing the CompareTo method defined by the interface.
Assigning an int value to a variable of type object causes what?
  • A. Unboxing
  • B. Boxing, where the value is wrapped in an object on the heap ✓
  • C. A compile error
  • D. A null reference
Correct answer: B. Storing a value type in an object reference boxes it onto the managed heap.
Given the statement var x = 10; what is the type of x?
  • A. dynamic
  • B. object
  • C. int, inferred by the compiler ✓
  • D. A type resolved only at runtime
Correct answer: C. var uses compile-time type inference, so x is strongly typed as int.
In ASP.NET Core you register a service with AddScoped. How long does a single instance live?
  • A. For the duration of a single HTTP request ✓
  • B. For the whole application lifetime
  • C. A fresh instance per method call
  • D. Forever until garbage collection
Correct answer: A. Scoped services are created once per HTTP request and shared within that request.
Using EF Core, you change a tracked entity's property and call SaveChanges(). What does EF do?
  • A. Deletes and re-inserts the row
  • B. Does nothing until a migration is run
  • C. Only updates the in-memory copy
  • D. Generates an UPDATE statement for the changed column ✓
Correct answer: D. The change tracker detects the modified property and emits an UPDATE on SaveChanges().
A static method can be called in what way?
  • A. Only after instantiating the class
  • B. Without creating an instance of the class ✓
  • C. Only from within the constructor
  • D. Only from other static classes
Correct answer: B. Static members belong to the type itself and are invoked without an instance.
The declaration int? x = null; compiles successfully. Why?
  • A. Because a plain int can always hold null
  • B. Because null is treated as zero
  • C. Because int? is a nullable value type that can hold null ✓
  • D. Because it is actually a compile error
Correct answer: C. int? is Nullable<int>, a value type that can represent an int or null.
A List<int> holds 3 items. Accessing list[3] throws which exception?
  • A. ArgumentOutOfRangeException ✓
  • B. NullReferenceException
  • C. StackOverflowException
  • D. InvalidCastException
Correct answer: A. The List<T> indexer validates the index and throws ArgumentOutOfRangeException when it is out of bounds.
An async method that performs work but returns no value should have which return type (best practice)?
  • A. void
  • B. int
  • C. IEnumerable
  • D. Task ✓
Correct answer: D. Returning Task (not async void) lets callers await completion and observe exceptions.
To let a derived class supply its own implementation of a base class method, the base method must be marked with which keyword?
  • A. sealed
  • B. virtual ✓
  • C. static
  • D. const
Correct answer: B. A method must be virtual (or abstract) before a derived class can override it.

Medium round 29 questions

You have a method that queries a database and you want the calling thread to remain responsive without blocking while awaiting the result. Which approach is correct?
  • A. Mark the method async and use await on the asynchronous database call, returning Task or Task<T> ✓
  • B. Call the database method and immediately call .Result to unwrap the value
  • C. Wrap the call in a new Thread and join it before returning
  • D. Mark the method async void and await inside it
Correct answer: A. Making the method async and awaiting the async call returns a Task/Task<T> and avoids blocking, while async void should be reserved for event handlers and .Result can deadlock.
In ASP.NET Core, which service lifetime creates a single instance per HTTP request, shared across all components handling that request?
  • A. Transient
  • B. Scoped ✓
  • C. Singleton
  • D. Instanced
Correct answer: B. Scoped services are created once per client request (scope), whereas Transient creates a new one each time and Singleton lives for the app's lifetime.
Using Entity Framework Core, you load a list of orders and access order.Customer.Name in a loop, triggering a separate query per order. What is this problem commonly called and how is it typically fixed?
  • A. N+1 query problem; fix with eager loading via .Include(o => o.Customer) ✓
  • B. Deadlock; fix by adding a transaction scope
  • C. Connection leak; fix by disposing the DbContext sooner
  • D. Cartesian explosion; fix by adding AsNoTracking()
Correct answer: A. Lazy-loading a related entity inside a loop causes the N+1 query problem, resolved by eager loading the related data with .Include.
What is the primary difference between IEnumerable<T> and IQueryable<T> when working with a database via LINQ?
  • A. IQueryable executes the query in the database, while IEnumerable pulls data into memory and filters client-side ✓
  • B. IEnumerable is strongly typed while IQueryable is not
  • C. IQueryable only works with arrays; IEnumerable works with any collection
  • D. There is no practical difference; they are interchangeable
Correct answer: A. IQueryable builds an expression tree translated to SQL and executed on the server, whereas IEnumerable materializes results and applies operations in memory.
In a Web API controller, you need to return a 404 when a requested resource is not found. Which is the idiomatic approach in ASP.NET Core?
  • A. return NotFound(); ✓
  • B. throw new Exception("404");
  • C. return StatusCode(200, null);
  • D. Response.StatusCode = 404; return null;
Correct answer: A. NotFound() is the built-in helper that returns an HTTP 404 result cleanly from a controller action.
Which statement about async/await deadlocks is correct when calling async code from a synchronous context?
  • A. Blocking on an async call with .Result or .Wait() can deadlock when the captured synchronization context is needed to resume the continuation ✓
  • B. await always deadlocks unless ConfigureAwait(true) is used
  • C. Deadlocks only occur in multi-threaded console apps, never in web apps
  • D. Using Task.Run inside every async method prevents all deadlocks
Correct answer: A. Blocking synchronously on a Task can deadlock because the continuation needs the same context that is blocked waiting; using async all the way (or ConfigureAwait(false)) avoids it.
You want to guarantee an object like a database connection is disposed even if an exception is thrown. Which is the recommended C# construct?
  • A. A using statement (or using declaration) around the disposable object ✓
  • B. A try/catch that logs the exception
  • C. Calling GC.Collect() after using the object
  • D. Setting the object to null when done
Correct answer: A. The using statement ensures Dispose() is called via a try/finally under the hood, even when exceptions occur.
In dependency injection, why is it generally preferred to depend on an interface (e.g., IRepository) rather than a concrete class in your service constructors?
  • A. It decouples the consumer from the implementation, enabling easier testing (mocking) and swapping implementations ✓
  • B. Interfaces execute faster than concrete classes at runtime
  • C. Concrete classes cannot be registered in the DI container
  • D. Interfaces automatically make the class thread-safe
Correct answer: A. Programming to an interface enables loose coupling so implementations can be substituted or mocked in unit tests without changing consumers.
What does the async keyword do when applied to a method that contains no await expression?
  • A. The method runs synchronously and the compiler warns that it will run synchronously ✓
  • B. The method automatically runs on a background thread
  • C. It causes a compile-time error
  • D. It makes the method non-blocking regardless of its body
Correct answer: A. Without an await, the async method executes synchronously and the compiler emits a warning (CS1998) since there is nothing to await.
In EF Core, when should you use AsNoTracking() on a query?
  • A. For read-only queries where you don't intend to update the returned entities, to improve performance ✓
  • B. Whenever you plan to modify and save the entities back to the database
  • C. Only inside a transaction to prevent dirty reads
  • D. To force EF to reload navigation properties on every access
Correct answer: A. AsNoTracking skips setting up change tracking, which improves performance and memory use for read-only scenarios where updates aren't needed.
What is the difference between 'IEnumerable<T>' and 'IQueryable<T>' when querying a database with Entity Framework?
  • A. They are identical
  • B. IQueryable builds an expression tree translated to SQL and executed server-side; IEnumerable executes in memory (client-side) ✓
  • C. IEnumerable is faster for all database queries
  • D. IQueryable cannot be used with LINQ
Correct answer: B. IQueryable defers to the provider to translate the expression tree into SQL, while IEnumerable materializes and filters in memory.
In async/await, what does 'ConfigureAwait(false)' do?
  • A. Cancels the awaited task
  • B. Continues the awaited code without capturing the original synchronization context ✓
  • C. Runs the task synchronously
  • D. Retries the task on failure
Correct answer: B. ConfigureAwait(false) tells the continuation not to marshal back to the captured context, improving performance and avoiding deadlocks in library code.
In ASP.NET Core dependency injection, which lifetime creates a single instance shared across the entire application lifetime?
  • A. Transient
  • B. Scoped
  • C. Singleton ✓
  • D. Pooled
Correct answer: C. Singleton registers one instance for the app's lifetime; Scoped is per request, Transient is per resolution.
What is the primary difference between 'Task.Run' and 'async/await' for I/O-bound work?
  • A. Task.Run offloads work to a thread-pool thread (better for CPU-bound); async I/O uses no dedicated thread while waiting ✓
  • B. They behave identically
  • C. async/await always creates a new thread
  • D. Task.Run cannot return a value
Correct answer: A. For I/O-bound work, true async avoids blocking a thread; Task.Run is appropriate for offloading CPU-bound work to the thread pool.
In Entity Framework Core, what does the 'AsNoTracking()' method accomplish?
  • A. It disables change tracking for read-only queries, improving performance ✓
  • B. It prevents SQL injection
  • C. It enables lazy loading
  • D. It forces an immediate database write
Correct answer: A. AsNoTracking skips the change tracker, reducing overhead for read-only result sets.
In C#, what is 'boxing'?
  • A. Wrapping a method in a try/catch
  • B. Converting a value type to an object (reference type) on the heap ✓
  • C. Serializing an object to JSON
  • D. Grouping fields into a struct
Correct answer: B. Boxing converts a value type into an object reference, allocating it on the managed heap.
Which HTTP status code should a well-designed ASP.NET Core Web API return when a POST successfully creates a new resource?
  • A. 200 OK
  • B. 201 Created ✓
  • C. 204 No Content
  • D. 302 Found
Correct answer: B. 201 Created signals successful resource creation, typically with a Location header pointing to the new resource.
What is the purpose of the 'yield return' statement in C#?
  • A. To return from an async method
  • B. To lazily produce elements of an iterator one at a time without building the whole collection ✓
  • C. To throw an exception
  • D. To pause a thread
Correct answer: B. yield return implements an iterator that produces values on demand, enabling deferred/lazy enumeration.
In C#, what is the effect of declaring a field as 'readonly' versus 'const'?
  • A. No difference
  • B. readonly can be assigned at declaration or in a constructor at runtime; const must be a compile-time constant ✓
  • C. const can be assigned in any method
  • D. readonly must be static
Correct answer: B. readonly permits runtime assignment (constructor), whereas const is fixed at compile time and implicitly static.
In middleware ordering for ASP.NET Core, why must UseAuthentication be placed before UseAuthorization?
  • A. Order does not matter
  • B. Authentication establishes the user identity that authorization then evaluates ✓
  • C. Authorization creates the token authentication reads
  • D. Both must come after UseEndpoints
Correct answer: B. Authentication must run first to populate HttpContext.User before authorization can make access decisions.
In ASP.NET Core dependency injection, what is the lifetime difference between AddScoped and AddSingleton?
  • A. Scoped creates one instance per DI container app-wide; Singleton one per request
  • B. Scoped creates one instance per request (scope); Singleton creates one instance for the app's lifetime ✓
  • C. They are identical
  • D. Singleton instances are created per method call
Correct answer: B. Scoped services live one per request scope; Singleton services are created once and shared for the application's lifetime.
Why can capturing a loop variable in a closure inside a C# for-loop (pre-C# 5 foreach semantics) cause unexpected behavior?
  • A. Closures are not allowed in loops
  • B. The closure captures the variable itself, so all closures may observe the final value if the variable is shared across iterations ✓
  • C. The compiler copies the value automatically always
  • D. It causes a stack overflow
Correct answer: B. Closures capture the variable, not a snapshot; if one variable is shared across iterations, all lambdas see its final value.
What does 'await' do to the continuation of an async method by default in a context with a SynchronizationContext?
  • A. It blocks the calling thread until completion
  • B. It schedules the continuation back onto the captured SynchronizationContext unless ConfigureAwait(false) is used ✓
  • C. It always runs the continuation on a new thread
  • D. It discards the result
Correct answer: B. By default await captures the current SynchronizationContext and resumes the continuation there; ConfigureAwait(false) opts out.
In Entity Framework Core, what problem does eager loading with Include() solve?
  • A. It caches queries permanently
  • B. It loads related navigation-property data in the same query, avoiding the N+1 query problem ✓
  • C. It disables change tracking
  • D. It encrypts the connection
Correct answer: B. Include() eager-loads related entities in one query, preventing repeated lazy-load round trips (the N+1 problem).
What is the practical difference between 'const' and 'readonly' fields in C#?
  • A. They are interchangeable
  • B. const is a compile-time constant baked into callers; readonly can be set at runtime in a constructor and is resolved at runtime ✓
  • C. readonly can only hold strings
  • D. const fields can be modified in methods
Correct answer: B. const is compile-time and inlined into referencing assemblies; readonly is assigned at runtime (declaration or constructor).
In a Web API, which HTTP status code should a POST that creates a resource ideally return, and with which header?
  • A. 200 OK with no headers
  • B. 201 Created with a Location header pointing to the new resource ✓
  • C. 204 No Content with an ETag
  • D. 404 Not Found
Correct answer: B. A successful creating POST should return 201 Created with a Location header referencing the newly created resource.
What is the risk of calling .Result or .Wait() on a Task in an ASP.NET (with SynchronizationContext) application?
  • A. It improves performance
  • B. It can cause a deadlock because the awaited continuation needs the context thread that is blocked waiting ✓
  • C. It automatically retries the task
  • D. It throws a compile error
Correct answer: B. Blocking on a Task can deadlock: the continuation needs the captured context thread, which is blocked waiting for the result.
In C#, what does the 'yield return' statement enable?
  • A. Parallel execution of a method
  • B. Lazy, on-demand generation of a sequence via an iterator without materializing the whole collection ✓
  • C. Returning multiple values as a tuple
  • D. Throwing an exception lazily
Correct answer: B. yield return builds a state-machine iterator that produces elements lazily as the consumer enumerates.
When would you choose a struct over a class in C#?
  • A. Always, for performance
  • B. For small, short-lived, immutable value-like data where copy semantics and avoiding heap allocation matter ✓
  • C. When you need inheritance
  • D. When you need null references
Correct answer: B. Structs suit small, immutable value-semantic data, avoiding heap allocation/GC pressure; they cannot use class inheritance.

Hard round 30 questions

A synchronous ASP.NET Core MVC action (running under the default request context in a legacy self-hosted scenario with a SynchronizationContext) calls `var data = GetDataAsync().Result;`. Inside `GetDataAsync`, an `await httpClient.GetStringAsync(url)` is used without `ConfigureAwait(false)`. The request hangs forever. What is the precise root cause?
  • A. The HttpClient instance is not thread-safe and blocks its own connection pool
  • B. The awaited continuation is posted back to the captured SynchronizationContext, whose only thread is already blocked on .Result waiting for that continuation ✓
  • C. GetStringAsync internally uses a ThreadPool thread that is exhausted by the blocking call
  • D. .Result throws an AggregateException that is silently swallowed, leaving the task incomplete
Correct answer: B. The await captures the single-threaded context; the continuation is queued to a thread that is blocked on .Result, so neither can proceed — ConfigureAwait(false) avoids capturing the context and breaks the deadlock.
Consider: `var actions = new List<Func<int>>(); for (int i = 0; i < 3; i++) actions.Add(() => i); Console.WriteLine(string.Join(",", actions.Select(a => a())));` in C# 4.0 semantics (pre-C# 5 foreach fix, classic for loop). What is printed?
  • A. 0,1,2
  • B. 3,3,3 ✓
  • C. 0,0,0
  • D. 2,2,2
Correct answer: B. A `for` loop's counter `i` is a single variable captured by reference by all closures, so after the loop each lambda reads the final value 3 — unlike `foreach`, which since C# 5 declares a fresh variable per iteration.
You register `IClock` (a Scoped service that reads a per-request tenant id) and inject it into a Singleton `CacheWarmer`. In production the warmer intermittently serves data for the wrong tenant. What is the correct explanation and fix?
  • A. Scoped services are thread-unsafe by design; wrap IClock access in a lock
  • B. The Singleton captured the first request's scoped IClock instance (captive dependency); inject IServiceScopeFactory and resolve IClock inside a created scope per operation ✓
  • C. Scoped lifetime is invalid for interfaces; re-register IClock as Transient to get a fresh instance each call
  • D. The DI container leaks the scope; call GC.Collect() after each request to release it
Correct answer: B. A Singleton resolving a Scoped dependency captures it once for the app's lifetime (the captive dependency problem); the fix is to inject IServiceScopeFactory and create a scope per unit of work.
This EF Core query loops `foreach (var o in ctx.Orders.ToList()) { total += o.Customer.Name.Length; }` with lazy loading enabled. Against 1,000 orders it issues 1,001 database round trips. Which single change eliminates the N+1 without changing tracked results?
  • A. Add `.AsNoTracking()` to the Orders query
  • B. Replace `.ToList()` with `.AsEnumerable()` to stream results
  • C. Use `ctx.Orders.Include(o => o.Customer).ToList()` so Customer is loaded in the same query ✓
  • D. Wrap the loop in a single explicit transaction with Serializable isolation
Correct answer: C. Each `o.Customer` access triggers a separate lazy-load query (the N+1); `Include` eager-loads Customer in the original query, collapsing 1,001 round trips into one.
A payment service receives the same 'charge $50' message twice due to at-least-once broker delivery. To make the handler idempotent so the customer is charged once, which design is correct and race-safe under concurrent duplicate delivery?
  • A. Check `SELECT` for an existing charge with the same idempotency key, then `INSERT` if absent — in two separate statements
  • B. Persist the charge with the client-supplied idempotency key under a UNIQUE constraint in the same transaction as the charge, treating a duplicate-key violation as 'already processed' ✓
  • C. Add a 5-second in-memory dedup cache of recently seen message ids on each service instance
  • D. Configure the broker for exactly-once delivery so the handler needs no idempotency logic
Correct answer: B. A non-atomic check-then-insert has a TOCTOU race under concurrency; a UNIQUE constraint on the idempotency key committed atomically with the charge lets the database enforce single-charge semantics, and exactly-once broker delivery is generally unattainable end-to-end.
In an ASP.NET Core pipeline, a developer writes `app.UseRouting(); app.UseEndpoints(...); app.UseAuthorization();` (authorization added AFTER endpoints). Requests to `[Authorize]` endpoints succeed even when unauthenticated. Why?
  • A. UseAuthorization only works with cookie auth, not JWT bearer
  • B. The authorization middleware is registered after the endpoint has already executed, so its policy check never runs for the matched endpoint ✓
  • C. Endpoint routing disables all middleware ordering, so position is irrelevant
  • D. UseAuthorization must be called before UseRouting to build the endpoint graph
Correct answer: B. Middleware runs in registration order; placing UseAuthorization after the endpoint execution means the terminal endpoint handles the request before the authorization check can enforce the policy.
Under sudden load, a service that does `httpClient.GetAsync(...).GetAwaiter().GetResult()` on every request sees requests time out and thread count climb, even though CPU is near-idle. What is happening?
  • A. Thread pool starvation: each request blocks a pool thread on I/O, the pool grows only ~1 thread/500ms, so incoming work queues faster than threads are injected ✓
  • B. The garbage collector is pausing all threads in a Gen 2 full collection under load
  • C. HttpClient's connection pool is exhausted, forcing synchronous DNS lookups on each call
  • D. The CLR is JIT-recompiling the hot path repeatedly, consuming threads
Correct answer: A. Sync-over-async blocks a thread pool thread for the whole I/O duration; the pool injects new threads slowly, so under load the queue outpaces thread injection — classic thread pool starvation despite idle CPU.
You have `struct Point { public int X; public void Inc() => X++; }` and store instances in a `List<Point>`. Calling `myList[0].Inc()` does not change the stored value, but calling `Inc()` on a `Point[]` element via `myArray[0].Inc()` does. Why the difference?
  • A. List<T> boxes value types on insertion, so Inc mutates a boxed copy
  • B. List<T>'s indexer returns a copy of the struct (a method call), while an array element access returns a direct reference to the element ✓
  • C. Arrays store structs by reference while List<T> stores them by value
  • D. The array version also fails; both leave the original unchanged
Correct answer: B. `List<T>`'s indexer is a property returning a by-value copy that Inc mutates and discards, whereas array indexing yields a direct addressable location so the in-place mutation sticks — a well-known mutable-struct trap.
A method returns `ValueTask<int>`. A caller writes `var vt = obj.ComputeAsync(); int a = await vt; int b = await vt;` where the implementation pools its IValueTaskSource. What is the correct assessment?
  • A. Fully safe — ValueTask is just a lightweight Task and can be awaited any number of times
  • B. Awaiting the same ValueTask twice is undefined behavior; the backing IValueTaskSource may be reset/reused, so the second await can throw or return a wrong/torn result ✓
  • C. The second await always returns the cached result with zero cost, which is the point of ValueTask
  • D. It only fails if the ValueTask wraps a Task; pooled sources are always safe to re-await
Correct answer: B. A ValueTask backed by a pooled IValueTaskSource must be consumed exactly once; the token/version can be recycled after the first await, making a second await undefined behavior.
A high-throughput producer/consumer needs bounded buffering with backpressure so fast producers block when consumers fall behind, plus native async consumption. Which primitive best fits and why over the alternatives?
  • A. `ConcurrentQueue<T>` with a busy-wait polling consumer loop for lowest latency
  • B. `Channel<T>` created bounded with `BoundedChannelFullMode.Wait`, exposing an async writer that yields on a full buffer and an IAsyncEnumerable reader ✓
  • C. `BlockingCollection<T>`, since its async support gives non-blocking backpressure out of the box
  • D. `List<T>` guarded by a single lock, resizing to absorb bursts
Correct answer: B. A bounded `Channel<T>` in Wait mode provides asynchronous, non-thread-blocking backpressure and native async reads; BlockingCollection blocks threads, ConcurrentQueue has no built-in bounding/backpressure, and a locked List is neither async nor bounded.
Consider `async Task M() { await Task.Delay(100); }` called as `M().Wait()` on a UI thread with a synchronization context. What is the classic risk?
  • A. A compile error
  • B. A deadlock because the continuation needs the UI thread that is blocked on Wait() ✓
  • C. An immediate NullReferenceException
  • D. The delay is skipped entirely
Correct answer: B. Wait() blocks the UI thread while the awaited continuation tries to resume on that same captured context, causing a deadlock.
In the .NET garbage collector, what best describes the purpose of the Large Object Heap (LOH)?
  • A. It stores objects >= 85,000 bytes and is collected with Gen 2, historically not compacted by default ✓
  • B. It stores all Gen 0 objects
  • C. It stores only string literals
  • D. It is compacted on every Gen 0 collection
Correct answer: A. Objects of ~85,000 bytes or larger go on the LOH, collected as part of Gen 2 and, by default, not compacted (compaction is opt-in).
Given `struct Point { public int X; }` used as a dictionary key implementing default equality, what performance concern arises with a struct that does not override GetHashCode/Equals?
  • A. It cannot be a key at all
  • B. Default ValueType.Equals/GetHashCode use reflection over fields, which can be slow ✓
  • C. It always boxes on every method call regardless
  • D. It causes a compile error
Correct answer: B. The default ValueType implementations can fall back to reflection-based field comparison/hashing, so overriding them is recommended for struct keys.
In EF Core, a query with `.Include()` on multiple collection navigations can cause a 'cartesian explosion'. Which feature mitigates this in modern EF Core?
  • A. AsNoTracking
  • B. Split queries via AsSplitQuery() ✓
  • C. Lazy loading proxies
  • D. Compiled models
Correct answer: B. AsSplitQuery() issues separate SQL queries per collection include, avoiding the row multiplication of a single joined query.
What does the C# `Span<T>` type provide that a normal array reference does not, and what is its key constraint?
  • A. Heap-only storage; can be a class field
  • B. A contiguous memory view (stack or heap, incl. stackalloc) that is a ref struct and cannot be boxed or used across await ✓
  • C. Automatic thread safety
  • D. Garbage-collection immunity for all referenced memory
Correct answer: B. Span<T> is a ref struct giving a zero-copy view over contiguous memory, but being stack-only it cannot be boxed, stored on the heap, or captured across await/yield.
In ASP.NET Core, injecting a Scoped service into a Singleton via constructor causes what?
  • A. Nothing; it is recommended
  • B. A captive dependency: the scoped service is effectively promoted to singleton lifetime, risking stale/incorrect state ✓
  • C. A guaranteed compile error
  • D. The singleton becomes transient
Correct answer: B. This is the captive dependency problem—the scoped instance lives as long as the singleton, defeating its per-request semantics.
When implementing IDisposable with the full Dispose pattern, why include a finalizer (~Class) and call GC.SuppressFinalize(this) in Dispose?
  • A. To force immediate garbage collection
  • B. The finalizer is a safety net for unmanaged resources; SuppressFinalize avoids the costly extra finalization pass once Dispose already cleaned up ✓
  • C. To make the class thread-safe
  • D. To prevent the object from ever being collected
Correct answer: B. The finalizer guards unmanaged resources if Dispose is missed; SuppressFinalize removes the object from the finalization queue when Dispose already ran.
In C#, what is the difference between `Task` continuation behavior with `ValueTask<T>` and `Task<T>` for a frequently-synchronous async method?
  • A. ValueTask always allocates more
  • B. ValueTask<T> can avoid heap allocation when the result is available synchronously, but must not be awaited more than once ✓
  • C. They are interchangeable in all cases with no rules
  • D. ValueTask cannot be awaited
Correct answer: B. ValueTask<T> reduces allocations for synchronously-completing paths but carries the constraint that it should be consumed (awaited) only once.
A high-throughput API sees thread-pool starvation under load. Which pattern is the most likely root cause?
  • A. Using async/await for all I/O
  • B. Synchronously blocking on async calls (e.g., .Result/.Wait) which ties up pool threads ✓
  • C. Registering services as Transient
  • D. Enabling response compression
Correct answer: B. Blocking on async (sync-over-async) consumes pool threads while they wait, starving the pool under concurrency—true async avoids this.
Regarding string interning in .NET, what is true of two string literals with identical content within the same assembly?
  • A. They are always distinct objects
  • B. The compiler interns them so both references point to the same intern-pool instance ✓
  • C. They can never be compared with ==
  • D. Interning only happens at garbage collection
Correct answer: B. Compile-time literals are automatically interned, so identical literals share one reference in the intern pool.
In .NET's garbage collector, what is the purpose of the Large Object Heap (LOH) and why can it cause issues?
  • A. It stores all reference types
  • B. Objects >= ~85,000 bytes are allocated on the LOH, which historically was not compacted, leading to fragmentation ✓
  • C. It is a faster generation-0 heap
  • D. It only holds strings
Correct answer: B. Objects >= ~85KB go on the LOH, which by default is not compacted, so fragmentation can waste memory and cause OOM.
What subtle bug can arise from using 'async void' methods (other than event handlers)?
  • A. They run synchronously
  • B. Exceptions thrown cannot be caught by the caller via await and can crash the process ✓
  • C. They cannot contain await
  • D. They always deadlock
Correct answer: B. async void methods can't be awaited, so their exceptions propagate to the SynchronizationContext and may crash the app.
In EF Core, when tracking is enabled and you load an entity, modify it, then load the same key again in the same context, what happens?
  • A. A new instance is returned every time
  • B. The context returns the already-tracked instance (identity resolution), so your in-memory change is preserved and the DB values may be ignored ✓
  • C. It throws a concurrency exception
  • D. The entity is duplicated in the change tracker
Correct answer: B. EF Core's identity map returns the already-tracked instance for the same key, so a second load does not overwrite tracked changes.
Why might 'ValueTask<T>' be preferred over 'Task<T>' in a hot async path, and what is the caveat?
  • A. ValueTask is always faster and has no caveats
  • B. ValueTask can avoid heap allocation when results are often synchronous, but must not be awaited multiple times or accessed after consumption ✓
  • C. ValueTask cannot be awaited
  • D. ValueTask disables exceptions
Correct answer: B. ValueTask avoids allocations for frequently-synchronous results but must be consumed once; reusing it leads to undefined behavior.
What does the C# 'volatile' keyword guarantee in a multithreaded scenario?
  • A. Atomicity of compound operations like i++
  • B. It prevents certain compiler/CPU reorderings and ensures reads/writes go to main memory, but does not make compound operations atomic ✓
  • C. A full memory barrier around every method
  • D. That the field is thread-local
Correct answer: B. volatile enforces acquire/release ordering and fresh reads/writes but does not make read-modify-write operations atomic.
In ASP.NET Core middleware, what is the consequence of not calling 'await next(context)' in a middleware component?
  • A. The pipeline continues normally
  • B. The rest of the pipeline (downstream middleware and endpoint) is short-circuited and never executes ✓
  • C. It throws a compile-time error
  • D. It runs the next middleware twice
Correct answer: B. Omitting the call to next short-circuits the pipeline, so downstream middleware and the endpoint are skipped.
Boxing a value type in C# has what performance and correctness implication in a dictionary keyed by an interface?
  • A. It has no cost
  • B. Boxing allocates on the heap and creates a copy; mutating a boxed value type via interface affects only the box, causing subtle bugs ✓
  • C. It makes the value type immutable permanently
  • D. It converts the struct to a class definition
Correct answer: B. Boxing heap-allocates a copy; mutating through an interface changes the box, not the original, and adds GC pressure.
In a high-throughput API, why might you use IAsyncEnumerable<T> with 'await foreach' instead of returning Task<List<T>>?
  • A. It is required for all APIs
  • B. It streams items as they become available with backpressure, avoiding buffering the entire result set in memory ✓
  • C. It disables async entirely
  • D. It guarantees ordering that List cannot
Correct answer: B. IAsyncEnumerable streams results incrementally, reducing memory pressure versus materializing the whole list before returning.
What is a potential pitfall of registering a Scoped service as a dependency of a Singleton in ASP.NET Core DI?
  • A. It works fine with no consequences
  • B. The Scoped instance gets captured (captive dependency) and effectively becomes a singleton, potentially outliving its intended scope and causing stale/threading issues ✓
  • C. It throws at compile time always
  • D. Singletons cannot have dependencies
Correct answer: B. A captive dependency: the scoped service is captured by the singleton and lives for the app lifetime, breaking scope semantics.
In C# pattern matching, what does the compiler do with an exhaustive switch expression over an enum missing a case at runtime with an unmapped value?
  • A. Returns default(T) silently
  • B. Throws a SwitchExpressionException at runtime because no arm matched ✓
  • C. Skips the switch
  • D. Compiles to an infinite loop
Correct answer: B. A switch expression with no matching arm (and no discard) throws SwitchExpressionException at runtime.

Prep for another role

Questions are original, written and independently verified for HireHire's role interview quizzes. They reflect the kind of knowledge .NET Developer interviews test, not any specific company's questions. HireHire maps live tech & IT jobs across India, updated regularly. Last updated: August 2026.