Imagine i've got a method which returns List of value types:
static List<SomeValueType> AllocateList()
List<SomeValueType> lst = new List<SomeValueType>();
for (int i = 0; i < 1000000; i++)
lst.Add(new SomeValueType("....", "..."));
List<T> is a reference type. Since it is the encapsulating object,
SomeValueType will be allocated on the heap, not the stack. More precisely, after the allocation of
SomeValueType on the stack, it will be lifted to the underlying storage of the
List<T>, which is on the heap. Thus, there will be no need for stack frame copying or the likes, and there will also be no need for boxing.
Value Types are stack allocated as an implementation detail, they can be allocated on the heap without any need for boxing, same way an
int is allocated on the heap.