Two kinds of type
Every C# type is either a value type or a reference type. A value-type variable holds the value itself. A reference-type variable holds a reference: an arrow to an object kept somewhere else, on the heap.
Value types: copy the value
int is a value type: a 32-bit whole number. The local variable a gets a slot in the method's stack frame, its scratch memory, and the number 5 sits right inside that slot.
Assigning a value type copies the value. b gets its own 5 in its own slot. a and b now hold equal values, but they are not connected in any way.
Line 3 puts 9 into b. a still holds 5, because b was only ever a copy. Changing a copy of a value never touches the original.
Reference types: share the object
Box is a class (line 8), and every class is a reference type. new builds one Box object on the heap and sets its field N (a variable inside the object) to 5. p does not hold the object: it holds a reference to it.
Assigning a reference type copies the reference, not the object. Now p and q are two arrows to the same Box. There is still only one object on the heap.
q.N means: follow q's arrow, then use the field N of that object. So line 6 sets the Box's N to 9. p points at that same Box, so p.N is now 9 too.
The result
$"..." is an interpolated string: each {name} is replaced by its value. The output is 5 9 9: a kept its own 5, b is 9, and p.N shows the change made through q.
Value types: int, double, bool, char, every struct and more. Reference types: every class, string, arrays and more. When an assignment surprises you, ask: did it copy the value, or only the arrow?
What happens
// step 1/9 · two-kinds
value type the variable holds the value int, double, bool, char, struct
reference type the variable holds a reference class, string, arrays
(an arrow to an object on the heap)
the heap memory for objects, run by .NET
The C# language only promises the copy rules. Where data lives is the runtime's choice: here the four locals sit in the method's stack frame (or in CPU registers), and the Box lives on the managed heap. A value that is part of an object, like N, lives inside that object. A reference-type variable can also hold null: no arrow at all. Using q.N when q is null throws a NullReferenceException.