All standalone heap objects inherit from
Object; that makes sense because all standalone heap objects must have certain common aspects, such as a means of identifying their type. Otherwise, if the garbage-collector had a reference to a heap object of unknown type, it would have no way of knowing what bits within the blob of memory associated with that object should be regarded as references to other heap objects.
Further, within the type system, it is convenient to use the same mechanism for defining the members of structures and the members of classes. The behavior of value-type storage locations (variables, parameters, fields, array slots, etc.) is very different from that of class-type storage locations, but such behavioral differences are achieved in the source-code compilers and execution engine (including the JIT compiler) rather than being expressed in the type system.
One consequence of this is that defining a value type effectively defines two types--a storage-location type and a heap-object type. The former may be implicitly converted to the latter, and the latter may be converted to the former via typecast. Both types of conversion work by copying all public and private fields from one instance of the type in question to another. Additionally, it is possible using generic constraints to invoke interface members on a value-type storage location directly, without making a copy of it first.
All of this is important because references to value-type heap objects behave like class references and not like value types. Consider, for example, the following code:
string testEnumerator<T>(T it) where T:IEnumerator<string>
var it2 = it;
public void test()
var theList = new List<string>();
var enum1 = theList.GetEnumerator();
IEnumerator<string> enum2 = enum1;
testEnumerator() method is passed a storage location of value type,
it will receive an instance whose public and private fields are copied from the passed-in value. Local variable
it2 will hold another instance whose fields are all copied from
it2 will not affect
If the above code is passed a storage location of class type, then the passed-in value,
it2, will all refer to the same object, and thus calling
MoveNext() on any of them will effectively call it on all of them.
Note that casting
IEnumerator<String> effectively turns it from a value type to a class type. The type of the heap object is
List<String>.Enumerator but its behavior will be very different from the value type of the same name.