# .NET Interview Gotchas

Questions interviewers love because the obvious answer is wrong. Know the behaviour **and** the fix.

## 1. Closures Capture Variables, Not Values

```csharp
var actions = new List<Func<int>>();
for (int i = 0; i < 3; i++) actions.Add(() => i);
actions.Select(a => a());   // 3, 3, 3: all lambdas share one `i`
```

`foreach` gets a fresh variable per iteration (since C# 5), `for` doesn't. Fix: copy to a local inside the loop (`int copy = i;`).

## 2. Mutating a Struct Copy

```csharp
var points = new List<MutablePoint> { new MutablePoint(1, 1) };
points[0].X = 5;           // compile error for List<T>; for other APIs you silently change a copy
var p = points[0]; p.X = 5; // changes the copy only
```

Fix: make structs immutable, assign the whole element back (`points[0] = points[0] with { X = 5 }`), or use a class.

## 3. Equality and Hashing

- `==` on classes compares **references** unless overloaded; records and strings compare values.
- Overriding `Equals` **requires** overriding `GetHashCode` consistently, or `Dictionary`/`HashSet` break.
- Mutating a field used in `GetHashCode` after inserting into a `HashSet` makes the item unfindable.
- Compare strings with an explicit `StringComparison` (`Ordinal`, `OrdinalIgnoreCase`); culture-sensitive comparisons produce surprises (the Turkish "I").

## 4. Numbers

- `double` can't represent 0.1 exactly: `0.1 + 0.2 != 0.3`. Use **`decimal` for money**.
- Integer overflow wraps silently unless in a `checked` context: `int.MaxValue + 1` is negative.
- Integer division truncates: `5 / 2 == 2`.

## 5. Dates and Times

- `DateTime.Now` is local time; servers should use **`DateTime.UtcNow`** or **`DateTimeOffset`**, and convert to local only for display.
- `DateTime.Kind` (`Utc`, `Local`, `Unspecified`) causes bugs when values cross systems; `DateTimeOffset` carries the offset.
- Inject `TimeProvider` to make time testable.

## 6. LINQ and Collections

- **Deferred execution**: a query runs each time it's enumerated; enumerating twice hits the database twice. Materialize with `ToList()` when you need it more than once.
- `First()` throws on empty; `FirstOrDefault()` returns default (null or 0).
- Modifying a collection while iterating with `foreach` throws `InvalidOperationException`.
- `IEnumerable` vs `IQueryable`: filtering after `AsEnumerable()` happens in memory.

## 7. Async and Exceptions

- `async void` crashes the process on exceptions; `Task.Run(async …)` without awaiting loses exceptions.
- `throw ex;` resets the stack trace; use `throw;`.
- `finally` runs even on `return`; `using` disposes even on exceptions.

## 8. Strings

Strings are immutable: `s.Replace("a", "b")` returns a new string and doesn't change `s`. `string.Empty` vs `null` vs whitespace: use `string.IsNullOrWhiteSpace`.

## Quick Reference

```text
closures capture variables (for-loop gotcha) · mutating struct copies · Equals ⇔ GetHashCode
decimal for money · overflow wraps (checked) · int division truncates
UtcNow / DateTimeOffset / TimeProvider · deferred LINQ execution · First vs FirstOrDefault
async void · throw; not throw ex; · strings immutable · explicit StringComparison
```
