C# Language Interview Q&A

C# Language Interview Q&A

Explore c# language interview q&a code snippets and tutorials

C# Language Interview Q&A

C# LINQ deferred execution, multiple enumeration and yield return

A LINQ query does not run when you write it, but when you enumerate it (foreach, ToList, Count, First).

csharp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// ======================================================================
// Q: What is deferred execution in LINQ?
//
// A LINQ query does not run when you write it, but when you enumerate it
// (foreach, ToList, Count, First). Each new enumeration runs it again (with EF:
// a new database query).
// ======================================================================

var query = db.Orders.Where(o => o.Status == OrderStatus.Placed);   // nothing yet
var count = query.Count();       // query 1
var list  = query.ToList();      // query 2: multiple enumeration

IEnumerable<int> Numbers()
{
    for (var i = 0; ; i++) yield return i;    // lazy: produces only as many as requested
}
var firstFive = Numbers().Take(5).ToList();
C# Language Interview Q&A

C# IEnumerable vs IQueryable with EF Core: in-memory filtering vs SQL

IQueryable<T> holds an expression tree that the provider (EF Core) translates to SQL.

csharp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// ======================================================================
// Q: IEnumerable vs IQueryable?
//
// IQueryable<T> holds an expression tree that the provider (EF Core) translates
// to SQL. IEnumerable<T> runs Where / Select in memory.
// That is why a repository returning IEnumerable from "GetAll" is a performance
// trap. IList / List: a materialized in-memory collection, with indexing and
// Count.
// ======================================================================

// ✗ the Where runs in memory: SELECT * FROM orders, then filtering in C#
IEnumerable<Order> all = db.Orders;
var big = all.Where(o => o.TotalNet > 1000).ToList();

// ✓ WHERE total_net > 1000 in the database
IQueryable<Order> query = db.Orders;
var big2 = query.Where(o => o.TotalNet > 1000).ToList();
C# Language Interview Q&A

C# boxing and unboxing: what it is and why it hurts performance

Converting a value type to object (or an interface): a copy is created on the heap.

csharp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// ======================================================================
// Q: What is boxing? Why does it matter?
//
// Converting a value type to object (or an interface): a copy is created on the
// heap. Unboxing is the reverse, with a type check. It costs allocations and GC
// on hot paths. Avoid it with generics (List<int> instead of ArrayList) and by
// not using object parameters.
// ======================================================================

int n = 42;
object o = n;          // boxing: allocation on the heap
int m = (int)o;        // unboxing
var list = new List<int> { n };   // no boxing: generic
C# Language Interview Q&A

C# value types vs reference types: class vs struct vs record explained

Value types (int, struct, enum): the value is copied on assignment.

csharp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// ======================================================================
// Q: Value types vs reference types. class vs struct vs record?
//
// - Value types (int, struct, enum): the value is copied on assignment. They
//   live inline (on the stack or inside the object that contains them).
// - Reference types (class, string, arrays): the variable holds a reference to
//   an object on the heap, which the GC cleans up.
// - struct: for small, immutable values (e.g. readonly struct Point). class: for
//   objects with identity and behavior. record: a reference type with value
//   equality, with-expressions and immutability. Ideal for DTOs and value
//   objects. There is also record struct.
// ======================================================================

public record Money(decimal Amount, string Currency);

var a = new Money(10, "EUR");
var b = a with { Amount = 20 };                 // new object, a does not change
Console.WriteLine(a == new Money(10, "EUR"));  // True: compares values, not references