and is therefore allocated on the stack (except for specific cases where it is boxed in a class for instance).
Is wrong. It is allocated as part of the declaring scope. There are probably more scenarios where it is actually on the heap than on the stack (simply: as part of another object - not an object itself), so this is not a good rule.
For your specific questions:
- the object that
items
refers to (the new List<int>()
) goes on the heap; the field items
is part of the struct
, where-ever that is (and just holds the reference - essentially a glorified pointer)
- the object will indeed be considered by GC when all references to it are out of scope
- that depends on who owns the lifetime of the object; if it is the
TestStruct
instance, then your best bet then would be for TestStruct
to actually be a class
that implements IDisposable
, and call Dispose()
from the class's Dispose()
As additional thoughts: being able to write g.items = new List<int>();
to me indicates that this is a very poor choice of a struct
, since mutability and struct
do not play nicely together (with lots of unexpected bugs possible). Either:
- make the
struct
immutable (i.e. a readonly
field, initialized in a custom constructor)
- make this a
class
In either case: a public
field is a bad choice - it should really be a property with a get
(and possibly a set
, if it is a class
- but probably not if it remains a struct
)
Examples:
public struct TestStruct {
private readonly List<int> items;
public List<int> Items { get { return items; } }
public TestStruct(List<int> items) {
this.items = items;
}
}
or:
public sealed class TestClass : IDisposable {
private SomeDisposable items = new SomeDisposable();
public SomeDisposable Items { get { return items; } }
public void Dispose() {
if(items != null) {
items.Dispose();
items = null;
}
}
}