# Modern C#: Records, Pattern Matching and Nullable Reference Types

## 1. Records

Records are types with **value-based equality**, built-in `ToString`, deconstruction and **non-destructive mutation** with `with`:

```csharp
public record Money(decimal Amount, string Currency);           // reference type, immutable positional properties
public readonly record struct Point(int X, int Y);              // value type
var price = new Money(10m, "EUR");
var discounted = price with { Amount = 8m };                    // copy with one change
Console.WriteLine(price == new Money(10m, "EUR"));              // True: compares values
```

Use records for DTOs, events, value objects and messages. Classes remain right for entities with identity and behaviour.

## 2. Pattern Matching

```csharp
string Describe(Shape s) => s switch
{
    Circle { Radius: 0 }            => "point",
    Circle c                        => $"circle r={c.Radius}",
    Rectangle { Width: var w, Height: var h } when w == h => $"square {w}",
    Rectangle r                     => $"rect {r.Width}x{r.Height}",
    null                            => "nothing",
    _                               => "unknown shape",
};

string Grade(int score) => score switch { >= 90 => "A", >= 80 and < 90 => "B", < 0 or > 100 => "invalid", _ => "C" };

string Summarize(int[] xs) => xs switch { [] => "empty", [var only] => $"one: {only}", [var first, .., var last] => $"{first}..{last}" };
```

Type patterns, property patterns, relational (`>=`), logical (`and`, `or`, `not`), positional patterns (deconstruction) and **list patterns** (C# 11) make branching declarative, and the compiler warns when a `switch` expression isn't exhaustive.

## 3. Nullable Reference Types

With `<Nullable>enable</Nullable>`, `string` means "never null" and `string?` means "may be null". The compiler tracks null-state through your code and warns on possible null dereferences or on assigning null to non-nullable types.

- Check with `is null` / `is not null`, use `?.` and `??`, `??=`.
- Attributes like `[NotNullWhen(true)]` teach the compiler about your helper methods (e.g. `TryGet`).
- The null-forgiving operator `!` silences a warning: use rarely, as a statement that you know better.
- Treat nullable warnings as errors in new code (`<WarningsAsErrors>nullable</WarningsAsErrors>`).

## 4. Other Features Worth Knowing

- **`required` members** and **`init`** setters: objects must be fully initialized at creation, yet immutable afterwards.
- **Primary constructors** on classes (C# 12): `class OrderService(IOrderRepository repo, ILogger<OrderService> log)`.
- **Collection expressions** (C# 12): `int[] xs = [1, 2, 3];`, `List<string> names = [..first, ..second];`.
- **File-scoped namespaces**, **global usings**, **raw string literals** (`"""…"""`), **`switch` on tuples**.
- **Static abstract interface members** enable generic math (`INumber<T>`).

## Common Pitfalls

1. **Records with mutable collections**: equality compares the collection reference, not contents.
2. **Using records for EF entities** with value equality: identity semantics get confusing.
3. **Non-exhaustive switch expressions** that throw `SwitchExpressionException` at runtime.
4. **Sprinkling `!`** to silence nullable warnings instead of fixing the flow.
5. **Overusing clever patterns** where a simple `if` reads better.

## Quick Reference

```text
record = value equality + with + ToString · record struct for small values · classes for entities
switch expressions: type, property, relational, logical, positional, list patterns · exhaustive
Nullable enabled: string vs string? · is null · ?. ?? ??= · [NotNullWhen] · avoid !
required/init · primary constructors · collection expressions [..a, ..b] · raw strings
```
