Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is ValueType.GetType() able to determine the type of the struct?

Tags:

c#

.net

types

For a reference type, the object's memory layout is

| Type Object pointer| |    Sync Block      | |  Instance fields...| 

For a value type, the object layout seems to be

|  Instance fields...| 

For a reference type, GetType means find the object from the 'Type Object pointer'. All objects of a given reference type object point to the same type object (which also has the method table)

For a value type, this pointer isn't available. So how does GetType() work ?

I checked with Google and I found this snippet.. which is a bit hazy. Can someone elaborate?

The solution is that the location in which a value is stored may only store values of a certain type. This is guaranteed by the verifier. Source

like image 420
Gishu Avatar asked May 29 '09 14:05

Gishu


People also ask

What is GetType?

GetType Method is used to find the type of the current instance. This method returns the instances of the Type class that are used for consideration. Syntax: public Type GetType (); Return Value: This method return the exact runtime type of the current instance.

How do I use GetType?

The GetType method is inherited by all types that derive from Object. This means that, in addition to using your own language's comparison keyword, you can use the GetType method to determine the type of a particular object, as the following example shows.


2 Answers

Calling GetType() on a value type boxes that value type. By moving the value type onto the heap you now have a reference type which now has a pointer to the type of that object.

If you wish to avoid boxing you can call GetTypeCode which returns an enumeration that indicates the type of the value type without boxing it.

Here is an example showing the boxing that takes place:

C#:

class Program {     static void Main()     {         34.GetType();     } } 

IL for Main():

.method private hidebysig static void Main() cil managed {         .entrypoint         .maxstack 8         L_0000: ldc.i4.s 0x22         L_0002: box int32         L_0007: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()         L_000c: pop          L_000d: ret  } 

Edit: To show what the compiler is doing, lets change the type of the literal like this:

class Program {     static void Main()     {         34L.GetType();     } } 

By adding the "L" after the literal I am telling the compiler that I want this literal to be converted to a System.Int64. The compiler sees this and when it emits the box instruction it looks like this:

.method private hidebysig static void Main() cil managed {         .entrypoint         .maxstack 8         L_0000: ldc.i4.s 0x22         L_0002: conv.i8          L_0003: box int64         L_0008: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()         L_000d: pop          L_000e: ret  } 

As you can see, the compiler has done the hard work of determining the correct instructions to emit, after that it is up to the CLR to execute them.

like image 147
Andrew Hare Avatar answered Sep 29 '22 16:09

Andrew Hare


Maybe Andrew H. took this as obvious and tried hard to make me understand +1. my light-bulb moment came from Jon Skeet.. again (this time via his book which I happened to be reading.. and around the exact region where the answers lay.

  • C# is a statically typed. Each variable has a type and it is known at compile time.
  • Value types can't be inherited. As a result, the VT objects don't need to carry around extra type information (as opposed to Ref Type objects, each of which have an object type header since the variable type and value/object type may differ.)

Consider the snippet below. Although the variable type is BaseRefType, it points to an object of a more specialized type. For value types, since inheritance is outlawed, the variable type is the object's type.

BaseRefType r = new DerivedRefType();  ValueType v = new ValueType(); 

My missing piece was bullet#1.
<Snipped after J.Skeet's comment since it seems to be wrong>. There seems to be some magic that lets the compiler/runtime know the 'type of the variable' given any arbitrary variable. So the runtime somehow knows that ob is of MyStruct type, even though the VT object itself has no type information.

MyStruct ob = new MyStruct(); ob.WhoAmI();                          // no box ; defined in MyStruct Console.WriteLine(ob.GetHashCode());  // no box ; overridden in ValueType Console.WriteLine( ob.GetType() );    // box ; implemented in Object 

Due to this, I am able to invoke methods defined in MyStruct (and ValueType for some reason) without boxing to a RefType.

like image 23
Gishu Avatar answered Sep 29 '22 15:09

Gishu