Skip to main content
Intervy
← All posts

C# Interview Questions That Test Production Judgment

·Intervy Team·10 min read
C# Interview Questions That Test Production Judgment
On this page

C# interview questions for experienced developers should expose what happens when a request outlives its caller, a resource closes too early or a query runs twice. Give candidates a small failure scenario and ask them to explain its mechanism before proposing a fix.

TL;DR: This bank offers ten scenarios with reference answers, neutral follow-ups and observable scoring anchors. Select questions relevant to the role, keep the starting conditions consistent and record the reasoning behind each rating.


Choose C# interview questions for the actual role

Use these as discussion prompts for mid-level and senior .NET backend hiring. The examples assume C# 12, .NET 8 and nullable annotations enabled; the request examples mean ASP.NET Core, and the collection example means LINQ to Objects.

  • Pick a request-path question, a cancellation question and an ownership or data-contract question.
  • Tell candidates whether a method performs I/O, who owns its resources and which failure they must investigate.
  • Accept equivalent safe designs when candidates explain their trade-offs.
  • Keep this bank separate from broader backend developer interview questions about architecture.

Tip: Naming an API is weaker evidence than tracing what happens when it fails.


C# interview questions: async work and cancellation

1. A request blocks on FetchAsync().Result. What would you change?

An ASP.NET Core request calls an I/O-bound FetchAsync method and reads its Task through .Result. Latency rises under load. Explain the mechanism and propose a repair.

Reference answer: Use await and keep the request path asynchronous through its callers. .Result occupies the request thread while waiting; many such waits can exhaust available worker threads. Wrapping the wait in Task.Run moves the blocking work rather than removing it. Do not diagnose a guaranteed deadlock: ASP.NET Core differs from older ASP.NET synchronization-context behavior.

Neutral follow-up: What observations would distinguish thread-pool starvation from a slow downstream service?

  • Weak: Replaces .Result without explaining why.
  • Adequate: Connects blocking waits to occupied request threads and awaits the operation.
  • Strong: Separates starvation from downstream latency and proposes checking thread-pool queues and dependency timing.

The request-path diagnosis follows Microsoft's ASP.NET Core best practices, which advises avoiding blocking calls.

2. A request starts SaveAsync without awaiting it. Who observes failure?

A handler calls SaveAsync(), discards the returned Task and immediately reports success. The save later faults. Explain what the response establishes.

Reference answer: The response does not establish that saving succeeded. For request-owned work, await the Task and handle failure at the intended boundary. A surrounding try/catch that never awaits the Task does not observe its later asynchronous fault. If acceptance before completion is a real requirement, define durable background ownership, retries and completion reporting separately.

Neutral follow-up: What should the caller see if the save fails before the response is sent?

  • Weak: Assumes invoking an async method means success.
  • Adequate: Awaits the save and observes its failure before reporting completion.
  • Strong: Distinguishes completed work from accepted background work and explains the ownership needed for the latter.

Microsoft's async programming guide explains how awaiting a faulted task observes its exception.

3. Two tasks fail inside WhenAll. What should diagnostics retain?

Two independent lookups are started, then awaited together with Task.WhenAll. Both fault. Explain completion and exception observation.

Reference answer: WhenAll finishes after every supplied task finishes; it is not a fail-fast cancellation mechanism. If any supplied task faults, the combined task faults. Awaiting it propagates one exception; retain the combined task and inspect its Exception collection when diagnostics require all failures.

Neutral follow-up: Does the first failure automatically cancel the other lookup?

  • Weak: Claims WhenAll stops or cancels its siblings on the first fault.
  • Adequate: Explains that all tasks finish and the combined task faults.
  • Strong: Distinguishes the exception surfaced by await from the aggregate retained on the combined task.

See Microsoft's Task.WhenAll reference for the combined task's completion and fault semantics.

4. The caller disconnects but downstream work continues. Where should cancellation go?

A request receives a cancellation token but calls FetchAsync without passing it. The client disconnects while the dependency is slow.

Reference answer: Pass the request token through each accepting layer to the actual asynchronous I/O operation. Cancellation is cooperative: requesting it does not forcibly kill arbitrary work. Avoid translating expected caller cancellation into a successful business result or indiscriminately retrying it. Already committed effects require a separate business decision.

Neutral follow-up: What would you test if one dependency ignores cancellation?

  • Weak: Calls Cancel and assumes everything stops immediately.
  • Adequate: Propagates the token to the operation that can stop.
  • Strong: Explains ignored tokens, observable termination and effects that may already have committed.

Microsoft's task cancellation guidance describes cancellation as cooperative.

5. How would you bound 5,000 asynchronous lookups?

A request creates one HTTP lookup per id and awaits Task.WhenAll over 5,000 ids. The dependency allows only a small number of simultaneous calls. Assume .NET 8.

Reference answer: WhenAll does not supply a concurrency limit. Use a bounded worker design, or Parallel.ForEachAsync with ParallelOptions.MaxDegreeOfParallelism and the request CancellationToken. Pass the body's token to each lookup and await the loop. Choose the limit from downstream capacity, then define partial-result and failure policy; do not write concurrently to an ordinary List without synchronization.

Neutral follow-up: What changes if each request respects its limit but many requests run together?

  • Weak: Adds WhenAll and assumes concurrency is bounded.
  • Adequate: Sets an explicit limit and propagates cancellation into each lookup.
  • Strong: Accounts for shared downstream capacity, safe result collection and partial failure.

The relevant overload accepts ParallelOptions; see Microsoft's Parallel.ForEachAsync reference.


Nullable contracts: what the compiler cannot promise

6. Does a non-nullable string parameter reject null input?

A public service accepts string name with nullable annotations enabled. A caller compiled without nullable warnings passes null. Explain the boundary.

Reference answer: Nullable reference annotations guide compiler analysis; they do not add an automatic argument guard. Validate inputs at the boundary according to the domain contract, then return a clear validation error or throw the chosen argument exception. Null, empty and whitespace are distinct policies.

Neutral follow-up: What should happen for an empty string, and who owns that rule?

  • Weak: Treats the annotation as an automatic null check.
  • Adequate: Adds an explicit null check at the service boundary.
  • Strong: Separates compiler intent from null, empty and whitespace domain rules.

Microsoft's nullable reference types guidance distinguishes static analysis from execution behavior.

7. A null-forgiving operator removes a warning. What changed?

A reviewer replaces customer.Name.Length with customer.Name!.Length after an uncertain lookup. Explain whether the failure mode changed.

Reference answer: The null-forgiving operator changes the compiler's null-state analysis, not the value or execution. A null name can still fail when dereferenced. Establish a real invariant, branch on absence or reject invalid data before use.

Neutral follow-up: What evidence would make the suppression justified here?

  • Weak: Says the operator makes the value non-null.
  • Adequate: Explains that execution is unchanged and handles absence.
  • Strong: Names the invariant and the boundary evidence needed to justify any suppression.

Microsoft's null-forgiving operator reference confirms that suppression changes analysis, not execution.


Resource lifetime and deferred LINQ work

8. A method returns ReadAsync from inside using. When is the resource disposed?

A method creates a FileStream in a using block, returns stream.ReadAsync(buffer, 0, buffer.Length), and leaves the block without awaiting. Assume the byte-array overload returns Task<int>.

Reference answer: The method leaves the using scope and disposes the stream before it knows the asynchronous read completed. A particular read may finish synchronously, so do not promise every call fails. Make the method async and await the read inside the scope before returning its result. Preserve ownership: callers should not dispose a resource owned elsewhere.

Neutral follow-up: Why can this pass a small-file test and still be unsafe?

  • Weak: Assumes returning the Task extends the using scope.
  • Adequate: Awaits the operation while the resource is alive.
  • Strong: Explains completion timing and distinguishes owned resources from borrowed resources.

Microsoft's using statement reference defines disposal on leaving the scope.

9. A resource implements IAsyncDisposable. How should cleanup complete?

An asynchronously opened resource implements IAsyncDisposable and requires asynchronous cleanup. Explain its intended lifetime in an async method.

Reference answer: Use await using so leaving the scope awaits DisposeAsync, including when the body throws. A using declaration keeps the resource until the end of its enclosing scope; choose a smaller block if it should be released sooner. Define ownership before disposing injected or shared objects.

Neutral follow-up: What changes when the method returns early or throws?

  • Weak: Relies on garbage collection or ignores the disposal Task.
  • Adequate: Uses await using and explains cleanup on scope exit.
  • Strong: Chooses the correct scope and states who owns cleanup for shared objects.

Microsoft's asynchronous disposal guidance explains the asynchronous cleanup contract.

10. Why does enumerating a LINQ query twice repeat work?

An IEnumerable<Order> query uses Where and a Select that records a side effect. The caller invokes ToList twice, changing the source between calls. Assume LINQ to Objects.

Reference answer: Where and Select defer the sequence work until enumeration; the query is not a cached snapshot. Two ToList calls enumerate it separately, can repeat the projection side effect and can observe different source values. If the contract needs one stable membership result, materialize once and reuse that list, accepting memory and freshness costs. Materialization does not deep-copy mutable elements; do not infer database-provider behavior from this example.

Neutral follow-up: What would you change if the sequence were too large to materialize?

  • Weak: Assumes assigning the query computes and caches its results.
  • Adequate: Explains repeated enumeration and materializes once when appropriate.
  • Strong: Weighs memory, freshness, mutable elements and a single-pass alternative.

Microsoft documents Where's deferred execution and the risks of multiple enumeration.


Turn answers into an interview decision

Treat the anchors above as an illustrative interviewer rubric, not a validated predictor of job performance or an automated score. A mid-level candidate might explain the local failure and propose a safe repair; a senior candidate should also examine ownership, downstream limits and how to distinguish competing causes. Set the required depth from the actual job.

Evidence to recordUseful noteMissing evidence
Failure mechanism“Explained that returning a task does not extend the resource scope.”Did not discuss a synchronously completed read.
Repair“Moved the await inside the owned scope.”Did not explain who disposes a borrowed stream.
Trade-off“Suggested materializing once for stable results.”Did not consider memory limits.

Use a neutral probe before concluding that evidence is absent. Ask “What happens if the operation fails?” rather than “Shouldn't you await it?” Record what the candidate said, which probe you supplied and what remains untested.

A structured interview tool or technical interview platform should support your agreed interview process; choosing a tool does not establish a hiring bar. For preparation and consistent follow-ups, pair this bank with the interviewer training practice plan.


Reuse the C# question bank

The matching set contains the same ten prompts, reference answers, follow-ups and illustrative anchors.

Intervy question bank showing categorized C# interview questions with difficulty and tags

To load all 10 questions, open the Import section, choose “C# Production Judgment” in Sample Interview Data and select Load. Importing requires organization membership and permission to update and publish questions; ask an organization admin if your role lacks either. The set is interview material: you remain responsible for assessing the candidate's explanation.

Key takeaway: A strong interview note connects an observed explanation to a role requirement. Keep the failure scenario, the candidate's reasoning and your rating together so the next interviewer can assess the evidence.

Related posts