public class MyClass
{
public int Age;
public int ID;
}
public void MyMethod()
{
MyClass m = new MyClass();
int newID;
}
To my un
The best resource I've seen for this is the book CLR via C# by Jeffrey Richter. It's well worth reading if you do any .NET development. Based on that text, my understanding is that the value types within a reference type do live in the heap embedded in the parent object. Reference types are always on the heap. Boxing and unboxing are not symmetric. Boxing can be a bigger concern than unboxing. Boxing will require copying the contents of the value type from the stack to the heap. Depending on how frequently this happens to you there may be no point in having a struct instead of a class. If you have some performance critical code and you're not sure if boxing and unboxing is happening use a tool to examine the IL code of your method. You'll see the words box and unbox in the IL. Personally, I would measure the performance of my code and only then see if this is a candidate for worry. In your case I don't think this will be such a critical issue. You are not going to have to copy from the stack to the heap (box) every time you access this value type inside the reference type. That scenario is where boxing becomes a more meaningful problem.
Reference Types(RT) always yield instances that are allocated on the heap. In contrast, value types(VT) are dependent on the context - If a local var is a VT, the CLR allocates memory on the stack. If a field in a class is a member of a VT, then the CLR allocates memory for the instance as part of the layout of the object/Type in which field is declared.
Ans#2: No. Boxing would occur only when you access a struct via a Object Reference / Interface Pointer. obInstance.VT_typedfield will not box.
RT variables contains the address of the object it refers to. 2 RT var can point to the same object. In contrast, VT variables are the instances themselves. 2 VT var cannot point to same object(struct)
Ans#3: Don Box's Essential .net / Jeffrey Richter's CLR via C#. I have a copy of the former... though the later may be more updated for .Net revisions
Value-type values for a class have to live together with the object instance in the managed heap. The thread's stack for a method only lives for the duration of a method; how can the value persist if it only exists within that stack?
A class' object size in the managed heap is the sum of its value-type fields, reference-type pointers, and additional CLR overhead variables like the Sync block index. When one assigns a value to an object's value-type field, the CLR copies the value to the space allocated within the object for that particluar field.
Take for example, a simple class with a single field.
public class EmbeddedValues
{
public int NumberField;
}
And with it, a simple testing class.
public class EmbeddedTest
{
public void TestEmbeddedValues()
{
EmbeddedValues valueContainer = new EmbeddedValues();
valueContainer.NumberField = 20;
int publicField = valueContainer.NumberField;
}
}
If you use the MSIL Disassembler provided by the .NET Framework SDK to peek at the IL code for EmbeddedTest.TestEmbeddedValues()
.method public hidebysig instance void TestEmbeddedValues() cil managed
{
// Code size 23 (0x17)
.maxstack 2
.locals init ([0] class soapextensions.EmbeddedValues valueContainer,
[1] int32 publicField)
IL_0000: nop
IL_0001: newobj instance void soapextensions.EmbeddedValues::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4.s 20
IL_000a: stfld int32 soapextensions.EmbeddedValues::NumberField
IL_000f: ldloc.0
IL_0010: ldfld int32 soapextensions.EmbeddedValues::NumberField
IL_0015: stloc.1
IL_0016: ret
} // end of method EmbeddedTest::TestEmbeddedValues
Notice the CLR is being told to stfld the loaded value of "20" in the stack to the loaded EmbeddValues' NumberField field location, directly into the managed heap. Similarly, when retrieving the value, it uses ldfld instruction to directly copy the value out of that managed heap location into the thread stack. No box/unboxing happens with these types of operations.
Do value types within objects live on the stack or the heap?
On the heap. They are part of the allocation of the footprint of the object, just like the pointers to hold references would be.
Is boxing/unboxing value types in an object a concern?
There's no boxing here.
Are there any detailed, yet understandable, resources on this topic?
+1 vote for Richter's book.
A variable or other storage location of a structure type is an aggregation of that type's public and private instance fields. Given
struct Foo {public int x,y; int z;}
a declaration Foo bar;
will cause bar.x
, bar.y
, and bar.z
to be stored wherever bar
is going to be stored. Adding such a declaration of bar
to a class will, from a storage-layout perspective, be equivalent to adding three int
fields. Indeed, if one never did anything with bar
except access its fields, the fields of bar
would behave the same as would three fields bar_x
, bar_y
, and bar_cantaccessthis_z
[accessing the last one would require doing things with bar
other than accessing its fields, but it would take up space whether or not it's ever actually used for anything].
Recognizing structure-type storage locations as being aggregations of fields is the first step to understanding structures. Trying to view them as holding some kind of object might seem "simpler", but doesn't match how they actually work.