C# Interview Questions and Answers

The .NET runtime, LINQ, async/await, generics and object-oriented design.

Practise 10 random 5 peer-reviewed questions
C# Interview Syllabus & Preparation Strategy

Whether you are preparing for entry-level C# interview questions for freshers or senior software engineer interview questions addressing concurrency, scalability, and system architecture, this track provides peer-reviewed model answers with syntax walkthroughs, edge cases, and practical interview tips.

1 How does async/await work in C#? Medium

async/await enables asynchronous programming without blocking a thread. Marking a method async lets you await a Task or Task<T>, and the compiler rewrites the method into a state machine. When the awaited operation is incomplete, control returns to the caller and resumes via a continuation when it completes.

public async Task<string> FetchAsync(HttpClient client, string url) {
    string body = await client.GetStringAsync(url);
    return body.Trim();
}

var text = await FetchAsync(client, url);

Key points: async void is only for event handlers, because callers cannot catch its exceptions or await it. Return Task when there is no value. Do not block on async code with .Result or .Wait(), which can deadlock. Use ConfigureAwait(false) in library code to avoid capturing the synchronisation context. I/O-bound work benefits most; CPU-bound work belongs on Task.Run.

2 What is deferred execution in LINQ and why does it matter? Medium

LINQ queries over IEnumerable<T> are lazy: the query is a description that runs only when enumerated by foreach, ToList, Count, First or similar. Each enumeration re-executes the query.

var query = people.Where(p => p.Age > 18).Select(p => p.Name);
foreach (var n in query) Console.WriteLine(n); // executes now
var list = query.ToList();                     // executes again

This enables composition and streaming, but it causes pitfalls: querying a database executes SQL on each enumeration; capturing a mutable variable in a lambda can give surprising results; and a query over a List re-reads current contents each time. Materialise with ToList or ToArray when you need a snapshot or to avoid repeated work.

IQueryable<T> translates expression trees to provider-specific queries such as EF Core SQL, so keep it composable and avoid forcing client-side evaluation.

3 How do generics and constraints work in C#? Medium

Generics let you write type-safe, reusable code without boxing or casts. The type parameter is resolved at compile time, and the JIT specialises for value types while sharing code for reference types.

public T Max<T>(T a, T b) where T : IComparable<T>
    => a.CompareTo(b) > 0 ? a : b;

public class Repo<T> where T : class, new() { }

Constraints include where T : class, struct, new(), a base class, one or more interfaces, notnull and unmanaged. Multiple constraints are separated by commas and new() must be last. Without a constraint you can only use members of object, or use EqualityComparer<T>.Default.

Covariance (out) and contravariance (in) on generic interfaces and delegates let IEnumerable<string> be used as IEnumerable<object>. Generics improve performance by avoiding boxing and improve safety by removing casts.

4 Explain IDisposable, the using statement and finalizers. Medium

IDisposable provides deterministic release of unmanaged resources through Dispose(). The using statement or declaration guarantees Dispose runs even if an exception is thrown.

using var stream = File.OpenRead("data.bin"); // disposed at scope end

using (var conn = new SqlConnection(cs)) {
    conn.Open();
}

A finalizer (~Type()) is a non-deterministic safety net run by the GC for types that directly own unmanaged handles. It runs on the finalizer thread and delays collection, so most code should not write one; use SafeHandle instead.

The full pattern uses Dispose(bool disposing) to release managed resources only during explicit disposal, and calls GC.SuppressFinalize(this). IAsyncDisposable with await using covers asynchronous cleanup. Never rely on the GC for files, sockets or locks, because it does not know about them.

5 When would you choose an interface over an abstract class? Medium

Both define contracts that other types implement, but they differ in intent and mechanics.

  • An interface declares a contract with no state (traditionally) and supports multiple implementation. Members are public by default, and C# 8+ allows default implementations. A class can implement many interfaces.
  • An abstract class can hold state (fields), constructors, and both abstract and concrete methods, but a class can inherit only one. It expresses an "is-a" relationship.
public interface IShape { double Area(); }

public abstract class Shape {
    public string Name { get; init; } = "";
    public abstract double Area();
    public override string ToString() => $"{Name}: {Area()}";
}

Prefer interfaces for capability-style contracts: they are multiple, decoupled and easy to mock in tests. Use an abstract class when implementations share code or state, or when you need to evolve the base with protected members over time.

Frequently Asked Questions About C# Interviews

What do hiring managers evaluate in C# technical rounds?

Technical interviewers look for foundational fluency, idiomatic syntax, clarity when communicating complex logic, and awareness of performance trade-offs (e.g. memory footprint, render performance, and network latency) in production environments.

What are the best interview tips for practicing C# questions?

Use active recall: summarize each answer in your own words before revealing the model solution. Focus on explaining why a certain approach is chosen rather than just memorizing code syntax.