# Records, Structs and Equality — C#/.NET

Source: https://www.skillbyai.com/en/dotnet/o-records

> Model immutable data with records and understand value equality.

## Data-centric types

A **record** is a type designed for data. `public record Customer(string Id, string Name);` is a **positional record**: the compiler generates init-only properties, a constructor, **deconstruction**, a readable `ToString()` and, most importantly, **value-based equality**: two records are equal if all their properties are equal, whereas two ordinary class instances are equal only if they are the same object. Records support **non-destructive mutation** with `with`: `var renamed = customer with { Name = "Ravi" };` creates a copy with one property changed. `record` (or `record class`) is a reference type; **`record struct`** is a value type with the same conveniences. Records suit DTOs, messages, value objects and events. A record holding a `List<T>` is still only shallowly immutable, and its equality compares the list reference, not its contents.

## Value equality and with-expressions

Equality compares contents, not identity.

```cs
public record Money(decimal Amount, string Currency)
{
    public Money Add(Money other) =>
        other.Currency == Currency
            ? this with { Amount = Amount + other.Amount }
            : throw new InvalidOperationException("Currency mismatch");
}

var a = new Money(100m, "INR");
var b = new Money(100m, "INR");
Console.WriteLine(a == b);              // True: same values
Console.WriteLine(ReferenceEquals(a, b)); // False: different objects

var (amount, currency) = a.Add(b);    // deconstruction
Console.WriteLine($"{amount} {currency}");
```

## Records in dictionaries and sets

Because equality and `GetHashCode` are based on values, records work well as dictionary keys, but only if they are truly immutable. Mutating a key after inserting it makes the entry impossible to find.

**Quiz:** Two record instances are created with identical property values. What does == return?

- [ ] False, because they are different objects
- [ ] It does not compile
- [x] True, because records use value-based equality
- [ ] It depends on the garbage collector

*Answer:* True, because records use value-based equality. Records generate equality members that compare property values.
