C# Interview Questions
C# Interview Questions
Section titled “C# Interview Questions”OOP & Language Fundamentals
Section titled “OOP & Language Fundamentals”Q: What is the difference between a class and a struct?
| Class | Struct | |
|---|---|---|
| Type | Reference type | Value type |
| Memory | Heap | Stack (usually) |
| Inheritance | Yes | No (can implement interfaces) |
| Default | null | Zero-initialized |
| Use case | Complex objects | Small, immutable data |
class Person { public string Name { get; set; } }struct Point { public int X; public int Y; }Q: What is the difference between abstract class and interface?
| Abstract Class | Interface | |
|---|---|---|
| Multiple inheritance | No | Yes |
| Fields | Yes | No (only properties) |
| Constructors | Yes | No |
| Access modifiers | Yes | Public by default |
| Implementation | Can have | Default methods (C# 8+) |
Use abstract class when sharing implementation. Use interface for contracts.
Q: What is boxing and unboxing?
int value = 42;object boxed = value; // boxing — value type → reference type (heap allocation)int unboxed = (int)boxed; // unboxing — reference type → value type
// Avoid in hot paths — causes GC pressureQ: What is the difference between == and .Equals()?
string a = new string("hello");string b = new string("hello");
Console.WriteLine(a == b); // True — string overloads ==Console.WriteLine(a.Equals(b)); // True
object x = 42;object y = 42;Console.WriteLine(x == y); // True — value comparison for boxed intsConsole.WriteLine(ReferenceEquals(x, y)); // False — different objectsQ: Explain virtual, override, and new keywords.
class Animal { public virtual string Speak() => "...";}
class Dog : Animal { public override string Speak() => "Woof"; // polymorphic override}
class Cat : Animal { public new string Speak() => "Meow"; // hides base method, not polymorphic}
Animal a = new Dog();Console.WriteLine(a.Speak()); // "Woof" — override is polymorphic
Animal b = new Cat();Console.WriteLine(b.Speak()); // "..." — new hides, not overridesQ: What is the difference between readonly and const?
class Config { public const double Pi = 3.14159; // compile-time, static, inlined public readonly DateTime StartTime; // runtime, set in constructor only
public Config() { StartTime = DateTime.Now; }}Async & Threading
Section titled “Async & Threading”Q: What is async/await and how does it work?
async/await is syntactic sugar over the Task-based Asynchronous Pattern (TAP). The compiler transforms the method into a state machine.
public async Task<string> FetchDataAsync(string url) { using var client = new HttpClient(); string result = await client.GetStringAsync(url); // non-blocking return result;}awaitsuspends the method without blocking the thread- The continuation runs when the awaited task completes
- Always use
ConfigureAwait(false)in library code
Q: What is the difference between Task and ValueTask?
Task: always allocates on the heapValueTask: avoids allocation when the result is already available (synchronous path)
// Use ValueTask when the method often completes synchronouslypublic ValueTask<int> GetCachedValueAsync() { if (_cache.TryGetValue("key", out int val)) return new ValueTask<int>(val); // no allocation return new ValueTask<int>(FetchAsync());}Q: What is deadlock and how do you avoid it in async code?
Deadlock occurs when .Result or .Wait() is called on a Task in a context that has a synchronization context (e.g., ASP.NET classic, WinForms):
// DEADLOCK — don't do thisvar result = GetDataAsync().Result;
// Safe options:// 1. Use await all the way upvar result = await GetDataAsync();
// 2. Use ConfigureAwait(false) in library codevar result = await GetDataAsync().ConfigureAwait(false);Q: What is the difference between IEnumerable and IQueryable?
IEnumerable<T> | IQueryable<T> | |
|---|---|---|
| Execution | In-memory (LINQ to Objects) | Translated to query (LINQ to SQL/EF) |
| Where filtering | Client-side | Server-side (SQL WHERE) |
| Use case | Collections, lists | Databases via EF Core |
// IQueryable — filter happens in SQLvar users = dbContext.Users.Where(u => u.Age > 18).ToList();
// IEnumerable — all users loaded, then filtered in memoryIEnumerable<User> users = dbContext.Users.ToList();var filtered = users.Where(u => u.Age > 18);Q: What is deferred execution in LINQ?
LINQ queries are not executed when defined — they execute when iterated:
var query = numbers.Where(n => n > 5); // not executed yet// ...foreach (var n in query) { } // executed here
// Force immediate executionvar list = numbers.Where(n => n > 5).ToList();Memory & Performance
Section titled “Memory & Performance”Q: What is the difference between Span<T> and Memory<T>?
Span<T>: stack-only, zero-allocation slice of contiguous memoryMemory<T>: heap-safe version, can be used in async methods
string text = "Hello, World!";ReadOnlySpan<char> span = text.AsSpan(0, 5); // "Hello" — no allocationConsole.WriteLine(span.ToString());Q: What is IDisposable and when should you implement it?
Implement IDisposable when your class holds unmanaged resources (file handles, DB connections, etc.):
public class FileProcessor : IDisposable { private FileStream _stream; private bool _disposed;
public FileProcessor(string path) { _stream = File.OpenRead(path); }
public void Dispose() { Dispose(true); GC.SuppressFinalize(this); }
protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) _stream?.Dispose(); _disposed = true; } }}Modern C# Features
Section titled “Modern C# Features”Q: What are records and when should you use them?
// Record — immutable reference type with value-based equalitypublic record Person(string Name, int Age);
var p1 = new Person("Alice", 30);var p2 = new Person("Alice", 30);Console.WriteLine(p1 == p2); // True — value equality
// Non-destructive mutationvar p3 = p1 with { Age = 31 };Use records for DTOs, value objects, and immutable data.
Q: What are primary constructors (C# 12)?
public class Service(ILogger logger, IRepository repo) { public void DoWork() { logger.Log("Working..."); repo.Save(); }}Q: What is pattern matching?
object obj = "Hello";
// Type patternif (obj is string s) Console.WriteLine(s.Length);
// Switch expressionstring result = obj switch { int n when n > 0 => "positive", string s when s.Length > 5 => "long string", null => "null", _ => "other"};
// Property patternif (person is { Age: > 18, Name: "Alice" }) { }Q: What is the difference between string and StringBuilder?
// string — immutable, each concat creates a new objectstring s = "";for (int i = 0; i < 1000; i++) s += i; // 1000 allocations — bad
// StringBuilder — mutable buffer, single allocationvar sb = new StringBuilder();for (int i = 0; i < 1000; i++) sb.Append(i);string result = sb.ToString();Q: What is dependency injection and how does it work in .NET?
// Register servicesbuilder.Services.AddScoped<IUserService, UserService>();builder.Services.AddSingleton<ICache, MemoryCache>();builder.Services.AddTransient<IEmailSender, SmtpEmailSender>();
// Inject via constructorpublic class UserController(IUserService userService) { public IActionResult Get(int id) => Ok(userService.GetById(id));}Lifetimes:
Singleton: one instance for the app lifetimeScoped: one per requestTransient: new instance every time