C#: Modern Features & Interview Questions
Records (C# 9+)
// Record — immutable reference type with value equality
public record User(int Id, string Name, string Email);
var alice = new User(1, "Alice", "alice@example.com");
var alice2 = new User(1, "Alice", "alice@example.com");
alice == alice2 // true — value equality (not reference)
alice.Equals(alice2) // true
// With expression — create copy with modifications
var alice3 = alice with { Email = "newalice@example.com" };
// Record struct (value type, stack-allocated)
public record struct Point(double X, double Y);
// Positional records with custom members
public record Order(int Id, List<Item> Items)
{
public decimal Total => Items.Sum(i => i.Price);
public bool IsEmpty => !Items.Any();
}
// Deconstruction
var (id, name, email) = alice;
// Primary constructors (C# 12) — for classes too
public class Service(ILogger<Service> logger, IRepository repo)
{
public async Task Process() => await repo.DoWork(); // logger, repo captured
}Pattern Matching (C# 7–11)
// Type pattern
if (shape is Circle c)
Console.WriteLine($"Circle: r={c.Radius}");
// Property pattern
if (user is { IsActive: true, Role: "admin" })
GrantAccess();
// List pattern (C# 11)
if (numbers is [1, 2, ..var rest])
Console.WriteLine($"Starts with 1, 2. Rest: {rest.Length} items");
// Switch expression with patterns
decimal Discount(Order order) => order switch
{
{ Total: > 1000, Customer.IsPremium: true } => 0.20m,
{ Total: > 500 } => 0.10m,
{ Items.Count: 0 } => 0m,
_ => 0.05m,
};
// Relational patterns (C# 9)
string Grade(int score) => score switch
{
>= 90 => "A",
>= 80 => "B",
>= 70 => "C",
< 0 => throw new ArgumentException("Negative score"),
_ => "F",
};
// Logical patterns
bool IsWorkday(DayOfWeek day) =>
day is not (DayOfWeek.Saturday or DayOfWeek.Sunday);Nullable Reference Types & Span
// Enable in .csproj: <Nullable>enable</Nullable>
// Now all reference types are non-nullable by default
string name = "Alice"; // cannot be null — compiler warns
string? nickname = null; // explicitly nullable
// Null-forgiving operator (tell compiler "trust me, not null")
string guaranteed = GetValue()!; // suppresses warning
// Required members (C# 11)
public class Config
{
public required string ConnectionString { get; init; } // must be set
public required int MaxConnections { get; init; }
}
var config = new Config
{
ConnectionString = "Server=...",
MaxConnections = 100
}; // compiler error if required properties missing
// Span<T> and Memory<T> — zero-copy slicing
void ProcessLine(ReadOnlySpan<char> line)
{
// Span — no heap allocation, can't be stored
var trimmed = line.Trim();
var parts = trimmed.IndexOf(':');
}
// stackalloc — stack allocation for small buffers
Span<int> buffer = stackalloc int[10];
for (int i = 0; i < buffer.Length; i++)
buffer[i] = i * 2;Interview Questions
What is the difference between class and struct? Class is a reference type (heap), struct is a value type (stack). Structs are copied on assignment. Use structs for small, immutable data (Point, Color). Classes for identity-based objects.
Explain boxing and unboxing. Boxing wraps a value type in an object (heap allocation). Unboxing extracts it. Avoid in hot paths — use generics (List<int> not ArrayList) to prevent boxing.
What is the difference between == and .Equals()? By default == compares references for classes; .Equals() can be overridden for value equality. Records override both for value equality. Always override both together.
What is IDisposable and the using statement? IDisposable.Dispose() releases unmanaged resources. using ensures Dispose() is called even if an exception occurs. using declaration (C# 8+): `using var conn = new SqlConnection(...)` — disposed at end of scope.
What is a delegate vs event? Delegate is a type-safe function pointer. Event wraps a delegate with access restrictions — outside classes can only += or -= not = (preventing replacement of all handlers).
Explain the difference between IEnumerable and IQueryable. IEnumerable pulls all data into memory then filters. IQueryable translates LINQ to SQL — filtering happens in the DB. Use IQueryable for EF Core to avoid loading unnecessary data.
What are expression trees? Data structures representing code as data. EF Core uses them to translate LINQ expressions to SQL. Created when assigning a lambda to Expression<Func<T, TResult>> instead of Func<T, TResult>.
What is the Task Parallel Library (TPL)? The foundation of async in .NET. Task represents an async operation. Task.Run() offloads work to the thread pool. async/await is syntactic sugar over TPL.
Difference between async Task and async void? async Task allows callers to await and catch exceptions. async void is fire-and-forget — exceptions go to the SynchronizationContext and can crash the app. Only use async void for event handlers.
What are extension methods? Static methods that appear as instance methods on a type. Defined in static classes with `this` as first parameter. LINQ is built entirely on extension methods on IEnumerable<T>.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free