Toolmingo
Guides21 min read

50 C# Interview Questions (With Answers)

Top C# interview questions with clear answers and code examples — covering OOP, LINQ, async/await, generics, delegates, memory management, and modern C# features.

C# interviews test knowledge of OOP principles, the .NET runtime, LINQ, async programming, and modern language features. This guide covers 50 of the most common questions — with concise answers and runnable code examples.

Quick reference

Topic Most asked questions
Types & Variables Value vs reference types, boxing, nullable
OOP Inheritance, abstract vs virtual, interfaces
Collections List, Dictionary, IEnumerable, LINQ
Delegates & Events Func/Action, lambda, event keyword
Generics Constraints, variance, generic collections
Async/Await Task, async/await, ConfigureAwait
Memory IDisposable, GC, using statement
Modern C# Records, pattern matching, nullable refs

Types and variables

1. What is the difference between value types and reference types?

Value types Reference types
Storage Stack (usually) Heap
Copy behaviour Copies the value Copies the reference
Default value Zero/false/null (struct) null
Examples int, bool, struct, enum class, interface, string, array
Nullable (legacy) int? / Nullable<int> Already nullable
int a = 10;
int b = a;   // b is an independent copy
b = 20;
Console.WriteLine(a); // 10 — unchanged

var list1 = new List<int> { 1, 2 };
var list2 = list1;   // both point to same object
list2.Add(3);
Console.WriteLine(list1.Count); // 3 — affected!

2. What is boxing and unboxing? Why is it a performance concern?

Boxing wraps a value type in a System.Object on the heap.
Unboxing extracts the value back out.

int n = 42;
object boxed = n;       // boxing — heap allocation
int unboxed = (int)boxed; // unboxing — explicit cast required

Why it matters:

  • Boxing allocates on the heap → GC pressure
  • Unboxing requires a type check → runtime cost
  • Avoid in hot paths; use generics (List<int> instead of ArrayList)

3. What is the difference between const and readonly?

const readonly
Set at Compile time Declaration or constructor
Instance or static Always static Can be instance or static
Types allowed Primitives, string, null Any type
Inlined by compiler Yes No
class Config
{
    public const int MaxRetries = 3;           // compiled into call sites
    public readonly DateTime CreatedAt;        // set in ctor

    public Config()
    {
        CreatedAt = DateTime.UtcNow;
    }
}

4. What is var and when should you use it?

var tells the compiler to infer the type. The type is still static — it's not dynamic.

var items = new List<string>();  // inferred as List<string>
var result = GetUser();          // inferred from return type

Use var when:

  • The right-hand side makes the type obvious
  • Working with LINQ results or anonymous types

Avoid var when the type adds clarity (int count = 0 is clearer than var count = 0).


5. What are nullable value types and nullable reference types?

Nullable value type (T? / Nullable<T>): allows null for value types.

int? age = null;
if (age.HasValue)
    Console.WriteLine(age.Value);
Console.WriteLine(age ?? 0); // null-coalescing

Nullable reference types (C# 8+, enable in project with <Nullable>enable</Nullable>):
Annotations warn when references might be null.

#nullable enable
string name = "Alice";   // non-nullable, must not be null
string? nickname = null; // nullable, may be null
Console.WriteLine(nickname?.ToUpper() ?? "no nickname");

Object-oriented programming

6. What are the four pillars of OOP?

Pillar C# example
Encapsulation Private fields with public properties
Inheritance class Dog : Animal
Polymorphism Virtual methods, method overriding
Abstraction Abstract classes and interfaces

7. What is the difference between a class and a struct?

Class Struct
Type Reference type Value type
Allocation Heap Stack (usually)
Inheritance Yes No (can implement interfaces)
Default ctor Implicit parameterless Always exists (zeroes fields)
Nullable Yes Only with Nullable<T>
Use case Complex objects, shared state Small data bags (Point, Color)
struct Point { public int X, Y; }
class Circle { public Point Center; public double Radius; }

8. What is the difference between abstract and virtual?

abstract class Shape
{
    public abstract double Area();   // no body, MUST be overridden
    public virtual string Describe() // has body, CAN be overridden
        => $"Shape with area {Area():F2}";
}

class Circle : Shape
{
    public double Radius { get; set; }
    public override double Area() => Math.PI * Radius * Radius;
}
abstract virtual
Body None Has default implementation
Override required Yes No
Class requirement Method must be in abstract class Any class

9. What is the difference between an interface and an abstract class?

Interface Abstract class
Instantiation Cannot Cannot
Multiple inheritance Yes (a class can implement many) No (single base class)
Fields No (only properties) Yes
Constructor No Yes
Access modifiers on members All public by default Any
Default implementations C# 8+ allowed Always allowed

Choose interface when defining a capability (IDisposable, IComparable).
Choose abstract class when sharing implementation across related types.


10. What is method overloading vs method overriding?

Overloading — same name, different parameters (compile-time polymorphism):

int Add(int a, int b) => a + b;
double Add(double a, double b) => a + b;

Overriding — redefines a virtual or abstract method in a subclass (runtime polymorphism):

class Animal { public virtual string Speak() => "..."; }
class Dog : Animal { public override string Speak() => "Woof"; }

11. What does the sealed keyword do?

sealed on a class prevents further inheritance; on a method, prevents further overriding.

sealed class Singleton { /* cannot be subclassed */ }

class Base { public virtual void Foo() {} }
class Child : Base { public sealed override void Foo() {} } // no further override

12. What is the difference between is and as?

object obj = "hello";

// is — returns bool, supports pattern matching
if (obj is string s)
    Console.WriteLine(s.Length);

// as — returns null if cast fails (only reference/nullable types)
string? text = obj as string;  // null if not string

is with pattern matching is preferred in modern C#.


Properties and indexers

13. What is the difference between a field and a property?

A field is a raw variable. A property is a field with accessor logic.

class Person
{
    private string _name = "";       // backing field

    public string Name               // property with validation
    {
        get => _name;
        set => _name = value?.Trim() ?? throw new ArgumentNullException();
    }

    public int Age { get; set; }     // auto-implemented property
    public int BirthYear { get; init; } // init-only (C# 9+)
}

Properties enable encapsulation, validation, lazy loading, and databinding.


LINQ

14. What is LINQ and what are its two syntax forms?

LINQ (Language Integrated Query) provides a unified way to query any IEnumerable<T> or IQueryable<T>.

Query syntax (SQL-like):

var evens = from n in numbers
            where n % 2 == 0
            orderby n
            select n * n;

Method syntax (fluent / lambda):

var evens = numbers
    .Where(n => n % 2 == 0)
    .OrderBy(n => n)
    .Select(n => n * n);

Both compile to the same IL. Method syntax is more composable.


15. What is deferred execution in LINQ?

LINQ queries are not executed when defined — they run when enumerated (with foreach, ToList(), Count(), etc.).

var query = numbers.Where(n => n > 5); // nothing executed yet
numbers.Add(10);                        // mutation before iteration
var result = query.ToList();            // executes NOW, 10 is included

Force immediate execution: .ToList(), .ToArray(), .ToDictionary(), .First().


16. What is the difference between IEnumerable<T> and IQueryable<T>?

IEnumerable<T> IQueryable<T>
Execution In-memory Translated (e.g., SQL)
Where filters at After data loaded Database side
Namespace System.Collections.Generic System.Linq
Use case LINQ to Objects LINQ to SQL / EF Core
// IQueryable — SQL WHERE is generated
var users = dbContext.Users.Where(u => u.IsActive); // SELECT ... WHERE IsActive=1

// IEnumerable — all rows loaded first, then filtered in C#
var users = dbContext.Users.AsEnumerable().Where(u => u.IsActive); // slow!

17. Common LINQ operators cheat sheet

Operator Purpose
Where Filter
Select Project / transform
SelectMany Flatten nested collections
OrderBy / ThenBy Sort ascending
GroupBy Group elements
Join / GroupJoin Inner / outer join
First / FirstOrDefault First element
Single / SingleOrDefault Exactly one element
Any / All Existential checks
Count / Sum / Average / Min / Max Aggregates
Distinct Remove duplicates
Skip / Take Pagination
Zip Combine two sequences pairwise
ToList / ToArray / ToDictionary Materialise

Delegates, events, and lambdas

18. What is a delegate?

A delegate is a type-safe function pointer.

delegate int MathOp(int a, int b);

MathOp add = (a, b) => a + b;
Console.WriteLine(add(3, 4)); // 7

// Multicast
MathOp log = (a, b) => { Console.WriteLine($"{a},{b}"); return 0; };
MathOp combined = add + log;
combined(1, 2);

The BCL provides generic delegates so you rarely define your own:

  • Action<T> — void return
  • Func<T, TResult> — non-void return
  • Predicate<T> — returns bool

19. What is an event?

An event is a delegate with publish/subscribe semantics — only the class can invoke it; external code can only subscribe/unsubscribe.

class Button
{
    public event EventHandler? Clicked;   // delegate field with event restriction
    public void Click() => Clicked?.Invoke(this, EventArgs.Empty);
}

var btn = new Button();
btn.Clicked += (sender, e) => Console.WriteLine("Clicked!");
btn.Click();

20. What is the difference between Action, Func, and Predicate?

Action<string> print = msg => Console.WriteLine(msg);       // void return
Func<int, int, int> add = (a, b) => a + b;                 // TResult return
Predicate<int> isEven = n => n % 2 == 0;                   // bool return

Predicate<T> is equivalent to Func<T, bool> but predates generics.


Generics

21. What are generics and why are they useful?

Generics allow writing type-safe code without specifying a concrete type at definition time.

// Without generics (boxing, runtime errors)
ArrayList list = new ArrayList();
list.Add(42);
int n = (int)list[0]; // cast required

// With generics (type-safe, no boxing)
List<int> typed = new List<int>();
typed.Add(42);
int m = typed[0];    // no cast

Benefits: type safety, no boxing, reusability, better IntelliSense.


22. What are generic constraints?

// T must be a class with a parameterless constructor
T Create<T>() where T : class, new() => new T();

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

// T must be a value type (struct)
void PrintBits<T>(T value) where T : struct { ... }
Constraint Meaning
where T : class Reference type
where T : struct Value type
where T : new() Has parameterless ctor
where T : SomeClass Inherits from SomeClass
where T : IFoo Implements interface
where T : notnull Non-nullable type

Collections

23. What is the difference between Array, List<T>, and LinkedList<T>?

Array List<T> LinkedList<T>
Fixed size Yes No (grows) No
Random access O(1) O(1) O(n)
Insert/delete at end O(1) Amortised O(1) O(1)
Insert/delete in middle O(n) O(n) O(1) (with node ref)
Memory Contiguous Contiguous Nodes with pointers

24. What is the difference between Dictionary<TKey,TValue> and HashSet<T>?

  • Dictionary: key → value mapping, O(1) average lookup
  • HashSet: unique elements only, O(1) average lookup/insert
  • Both use hash codes internally
var dict = new Dictionary<string, int> { ["a"] = 1 };
dict.TryGetValue("a", out int v); // preferred over dict["a"] to avoid KeyNotFoundException

var set = new HashSet<int> { 1, 2, 3 };
set.Add(2); // no-op, 2 already present
set.UnionWith(new[] { 3, 4, 5 }); // set operations built in

25. What is IEnumerable<T> vs ICollection<T> vs IList<T>?

IEnumerable<T>       — iterate only
  └── ICollection<T> — + Count, Add, Remove, Contains
        └── IList<T> — + index access [i], IndexOf, Insert

Program to the narrowest interface that meets your needs.


Async and await

26. What is async/await and how does it work?

async/await is syntactic sugar over the Task Parallel Library. The compiler rewrites the method into a state machine.

async Task<string> FetchAsync(string url)
{
    using var client = new HttpClient();
    string html = await client.GetStringAsync(url); // suspend, don't block thread
    return html.Length.ToString();
}

await suspends the method and returns control to the caller until the Task completes. The thread is not blocked — it can serve other work.


27. What is the difference between Task, Task<T>, and ValueTask<T>?

Task Task<T> ValueTask<T>
Return value None T T
Allocation Heap Heap Stack (when sync)
Use case Fire-and-forget style Async with result Hot paths / caching
async Task LogAsync() { await File.AppendAllTextAsync("log.txt", "ok"); }
async Task<int> CountAsync() { return await GetCountFromDbAsync(); }
async ValueTask<int> GetCachedAsync() { return _cache ?? await FetchAsync(); }

28. What does ConfigureAwait(false) do?

By default, await captures the current SynchronizationContext (e.g., UI thread) and resumes there. This is expensive in library code.

// Library code — no UI context needed
public async Task<Data> LoadAsync()
{
    var json = await File.ReadAllTextAsync(path).ConfigureAwait(false);
    return JsonSerializer.Deserialize<Data>(json)!;
}

ConfigureAwait(false) → resume on any thread pool thread. Use in libraries; usually not needed in ASP.NET Core (no SynchronizationContext there).


29. What is the difference between Task.Run and async/await?

  • async/await: non-blocking I/O; doesn't use an extra thread for I/O waits
  • Task.Run: offloads CPU-bound work to a thread pool thread
// I/O-bound — use async/await, no Task.Run needed
string content = await File.ReadAllTextAsync("file.txt");

// CPU-bound — offload to thread pool
int result = await Task.Run(() => Fibonacci(40));

30. How do you run multiple async tasks in parallel?

// Sequential — waits for each one
var a = await GetAAsync();
var b = await GetBAsync();

// Parallel — both start immediately
var taskA = GetAAsync();
var taskB = GetBAsync();
await Task.WhenAll(taskA, taskB);
var (a, b) = (taskA.Result, taskB.Result);

// First one wins
var first = await Task.WhenAny(taskA, taskB);

Exception handling

31. What is the difference between throw and throw ex?

try { RiskyOp(); }
catch (Exception ex)
{
    throw;     // ✅ preserves original stack trace
    throw ex;  // ❌ resets stack trace to this line
    throw new AppException("Context info", ex); // ✅ wraps with cause
}

Always prefer throw; to rethrow, or throw new ...(ex) to add context.


32. What is the finally block used for?

Code in finally always runs — even if an exception is thrown or a return is hit.

FileStream? fs = null;
try
{
    fs = File.OpenRead("data.bin");
    Process(fs);
}
finally
{
    fs?.Dispose(); // always runs
}

In modern C#, prefer the using statement or using declaration.


33. What are custom exceptions and when should you create them?

Create custom exceptions when callers need to distinguish your failure mode:

public class OrderNotFoundException : Exception
{
    public int OrderId { get; }
    public OrderNotFoundException(int id)
        : base($"Order {id} was not found.") => OrderId = id;
    public OrderNotFoundException(int id, Exception inner)
        : base($"Order {id} was not found.", inner) => OrderId = id;
}

Inherit from Exception for application exceptions, or ApplicationException (rarely used today).


Memory management

34. What is the IDisposable pattern and when is it needed?

Implement IDisposable when a class holds unmanaged resources (file handles, DB connections, network sockets) or references to other IDisposable objects.

public class FileWriter : IDisposable
{
    private StreamWriter? _writer;
    private bool _disposed;

    public FileWriter(string path) => _writer = new StreamWriter(path);

    public void Write(string text) => _writer?.WriteLine(text);

    public void Dispose()
    {
        if (_disposed) return;
        _writer?.Dispose();
        _disposed = true;
        GC.SuppressFinalize(this);
    }
}

// Usage
using var fw = new FileWriter("out.txt"); // Dispose called automatically
fw.Write("Hello");

35. How does the .NET garbage collector work?

.NET uses a generational, tracing GC:

Generation Contents Collected
Gen 0 New, short-lived objects Most frequently
Gen 1 Survived one collection Less often
Gen 2 Long-lived objects Least often
LOH Objects ≥ 85,000 bytes Gen 2 collections

Key points:

  • GC runs when Gen 0 is full, under memory pressure, or called explicitly
  • GC.Collect() — avoid in production; the GC knows better
  • Finalizers (~ClassName()) delay collection; prefer IDisposable
  • .NET 5+ uses the new region-based GC in server mode

Strings

36. Why is string immutable and when should you use StringBuilder?

string is a reference type but immutable — every operation creates a new string.

string s = "hello";
s += " world"; // new string allocated, old one eligible for GC

Use StringBuilder for many concatenations in a loop:

var sb = new StringBuilder();
for (int i = 0; i < 10_000; i++)
    sb.Append(i).Append(',');
string result = sb.ToString();

For a few concatenations, $"..." interpolation or string.Concat is fine.


Modern C# features

37. What are records (C# 9+)?

Records are immutable reference types with value equality semantics, ideal for DTOs.

record Person(string FirstName, string LastName);

var alice = new Person("Alice", "Smith");
var alice2 = alice with { LastName = "Jones" }; // non-destructive mutation

Console.WriteLine(alice == alice2);       // false (value equality)
Console.WriteLine(alice.FirstName);       // Alice
Console.WriteLine(alice);                 // Person { FirstName = Alice, LastName = Smith }

record struct (C# 10) — same but value type.


38. What is pattern matching?

Pattern matching tests values against a shape and binds parts.

object shape = new Circle(5.0);

string desc = shape switch
{
    Circle c when c.Radius > 10 => "big circle",
    Circle c                    => $"circle r={c.Radius}",
    Rectangle { Width: var w, Height: var h } => $"rect {w}×{h}",
    null                        => "null",
    _                           => "unknown"
};

Pattern types: type pattern, constant, relational (> 0), logical (and/or/not), property, positional, list (C# 11).


39. What are init-only properties (C# 9+)?

init allows setting a property during object initialization only — then it becomes read-only.

class Order
{
    public int Id { get; init; }
    public string Item { get; init; } = "";
}

var order = new Order { Id = 1, Item = "Book" };
// order.Id = 2; // compile error after init

40. What are nullable reference types (C# 8+)?

When enabled (<Nullable>enable</Nullable>), the compiler tracks nullability:

string name = "Alice";   // can't be null
string? nickname = null; // may be null

void Greet(string? nick)
{
    Console.WriteLine(nick?.ToUpper() ?? "no nickname");
    // nick.ToUpper() — warning: possible null dereference
}

Eliminates most NullReferenceExceptions at compile time.


Object equality and comparison

41. What is the difference between == and .Equals()?

For value types: both compare values.
For reference types: == compares references by default; .Equals() can be overridden.

string a = new string("hello".ToCharArray());
string b = new string("hello".ToCharArray());
Console.WriteLine(a == b);        // true  — string overloads ==
Console.WriteLine(object.ReferenceEquals(a, b)); // false — different objects

Always override Equals and GetHashCode together, and implement IEquatable<T>.


42. What is IComparable vs IComparer?

  • IComparable<T>: the type knows how to compare itself to another T
  • IComparer<T>: an external object that compares two T instances
class Product : IComparable<Product>
{
    public int Price { get; set; }
    public int CompareTo(Product? other) => Price.CompareTo(other?.Price);
}

// Custom external comparer
class ByName : IComparer<Product>
{
    public int Compare(Product? x, Product? y)
        => string.Compare(x?.Name, y?.Name, StringComparison.Ordinal);
}

products.Sort(new ByName());

Reflection and attributes

43. What are attributes and how are they used?

Attributes add declarative metadata to types, methods, and parameters.

[Obsolete("Use NewMethod instead", error: true)]
void OldMethod() { }

[Serializable]
class Config { }

// Custom attribute
[AttributeUsage(AttributeTargets.Property)]
class RequiredAttribute : Attribute { }

Read at runtime via reflection:

var attrs = typeof(Config).GetCustomAttributes<ObsoleteAttribute>();

Dependency injection and design patterns

44. What is dependency injection and how does ASP.NET Core support it?

DI decouples classes from their dependencies by injecting them rather than constructing them.

// Register in Program.cs
builder.Services.AddScoped<IOrderService, OrderService>();
builder.Services.AddSingleton<ICache, MemoryCache>();

// Constructor injection
public class OrderController : ControllerBase
{
    private readonly IOrderService _orders;
    public OrderController(IOrderService orders) => _orders = orders;
}

Service lifetimes:

Lifetime Created Typical use
Singleton Once per app Caches, config
Scoped Once per HTTP request DbContext, services
Transient Every injection Lightweight utilities

Extension methods

45. What are extension methods?

Extension methods add methods to existing types without modifying them.

public static class StringExtensions
{
    public static bool IsNullOrEmpty(this string? s) => string.IsNullOrEmpty(s);
    public static string Truncate(this string s, int maxLen)
        => s.Length <= maxLen ? s : s[..maxLen] + "…";
}

"Hello World".Truncate(5); // "Hello…"

Rules: must be in a static class, first parameter prefixed with this. LINQ is built entirely from extension methods.


Miscellaneous

46. What is dynamic and when should it be used?

dynamic bypasses compile-time type checking — resolved at runtime via the DLR.

dynamic obj = GetSomeObject();
obj.DoSomething(); // no compile error, but may throw at runtime

Use sparingly — primarily for COM interop, scripting scenarios, and deserialized JSON with unknown shape. Prefer object + casting or generics for type-safe code.


47. What is the yield keyword?

yield return creates an iterator — values are produced lazily on demand.

IEnumerable<int> EvenNumbers(int max)
{
    for (int i = 0; i <= max; i += 2)
        yield return i;   // pauses, caller gets value
}

foreach (var n in EvenNumbers(10))
    Console.Write(n + " "); // 0 2 4 6 8 10

yield break ends the sequence early. Useful for streaming large datasets without loading everything into memory.


48. What is Span<T> and Memory<T>?

Span<T> is a stack-allocated type that provides a window into contiguous memory — arrays, stack memory, or native memory — without allocation.

string csv = "Alice,30,Engineer";
ReadOnlySpan<char> span = csv.AsSpan();
int firstComma = span.IndexOf(',');
ReadOnlySpan<char> name = span[..firstComma]; // "Alice" — no allocation

Memory<T> is the heap-friendly version that can be stored in fields and used in async methods.

Use in high-performance, low-allocation parsing code.


49. What is the difference between == for strings and why does string interning matter?

The .NET runtime interns string literals — identical literals share the same memory address.

string a = "hello";
string b = "hello";
Console.WriteLine(object.ReferenceEquals(a, b)); // true — interned!

string c = new string("hello".ToCharArray()); // forces new allocation
Console.WriteLine(object.ReferenceEquals(a, c)); // false

// Force interning
string d = string.Intern(c);
Console.WriteLine(object.ReferenceEquals(a, d)); // true

For comparison, always use == (which calls Equals for strings) or string.Equals(a, b, StringComparison.Ordinal) — never rely on ReferenceEquals for value equality.


50. What are the most common C# anti-patterns?

Anti-pattern Problem Fix
catch (Exception) and swallow Hides bugs Rethrow or log and rethrow
async void (non-event) Exceptions lost Return Task
Blocking on Task with .Result/.Wait() Deadlocks in sync contexts await instead
new Thread() for async work Heavyweight Task.Run or async/await
Mutating IEnumerable<T> while iterating InvalidOperationException Copy to list first
string += in loop O(n²) allocations StringBuilder
Ignoring IDisposable Resource leaks using statement
God class Unmaintainable Single Responsibility Principle

Common mistakes

Mistake Why it breaks Fix
async void method Unobserved exceptions crash the app async Task
.Result on Task in ASP.NET Deadlock await
Not implementing GetHashCode with Equals Dictionary / HashSet breaks Always pair them
== on struct without override Compares all fields by reflection (slow) Override == / use record struct
foreach on IQueryable with no terminal N+1 queries ToList() once, then iterate
Capturing loop variable in lambda Closure captures by ref Copy: var captured = i;
Forgetting await in async method Returns immediately Always await or chain
List<T> exposed as public field External code can mutate Return IReadOnlyList<T>

C# vs Java vs Python

Feature C# Java Python
First-class async async/await (excellent) Virtual threads (Java 21) asyncio
Value types on stack struct Primitives only No
Properties Built-in Getters/setters @property
LINQ Built-in Streams API List comprehensions
Nullable safety C# 8+ annotations Optional Optional typing
Pattern matching Excellent (C# 8+) Good (Java 16+) match (3.10+)
Records record (C# 9+) record (Java 16+) @dataclass
Operator overloading Yes No __dunder__ methods

Frequently asked questions

Q: Is C# only for Windows?
A: No. .NET 5+ (including .NET 6/7/8/9) is cross-platform — Linux, macOS, Docker. .NET Framework (4.x) is Windows-only.

Q: When should I use a struct vs a class?
A: Use struct for small, immutable data with value semantics (Point, Color, DateTime). Use class for anything larger, mutable, or that needs inheritance.

Q: What is the difference between .NET Framework, .NET Core, and .NET 5+?
A: .NET Framework (Windows-only, legacy). .NET Core (cross-platform, modern, now called just .NET from version 5). .NET 5+ is the unified successor — use it for all new projects.

Q: What is async/await doing under the hood?
A: The compiler rewrites the method into a state machine. Each await point is a state. When resumed, the method continues from that state, freeing the thread between I/O waits.

Q: How do I choose between List<T>, IEnumerable<T>, and IReadOnlyList<T> for method signatures?
A: Accept the narrowest type (usually IEnumerable<T>). Return the most informative type without exposing mutability (IReadOnlyList<T> is better than List<T> for return values).

Q: What is the difference between Task.WhenAll and Task.WaitAll?
A: Task.WhenAll is async — returns a Task, doesn't block the thread. Task.WaitAll is synchronous — blocks the calling thread. Always prefer await Task.WhenAll(...).

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools