Details on what happens when a struct implements an interface

Earlz picture Earlz · Mar 4, 2013 · Viewed 8k times · Source

I recently came across this Stackoverflow question: When to use struct?

In it, it had an answer that said something a bit profound:

In addition, realize that when a struct implements an interface - as Enumerator does - and is cast to that implemented type, the struct becomes a reference type and is moved to the heap. Internal to the Dictionary class, Enumerator is still a value type. However, as soon as a method calls GetEnumerator(), a reference-type IEnumerator is returned.

Exactly what does this mean?

If I had something like

struct Foo : IFoo 
{
  public int Foobar;
}

class Bar
{
  public IFoo Biz{get; set;} //assume this is Foo
}

...

var b=new Bar();
var f=b.Biz;
f.Foobar=123; //What would happen here
b.Biz.Foobar=567; //would this overwrite the above, or would it have no effect?
b.Biz=new Foo(); //and here!?

What exactly are the detailed semantics of a value-type structure being treated like a reference-type?

Answer

supercat picture supercat · Mar 4, 2013

Every declaration of a structure type really declares two types within the Runtime: a value type, and a heap object type. From the point of view of external code, the heap object type will behave like a class with a fields and methods of the corresponding value type. From the point of view of internal code, the heap type will behave as though it has a field this of the corresponding value type.

Attempting to cast a value type to a reference type (Object, ValueType, Enum, or any interface type) will generate a new instance of its corresponding heap object type, and return a reference to that new instance. The same thing will happen if one attempts to store a value type into a reference-type storage location, or pass it as a reference-type parameter. Once the value has been converted to a heap object, it will behave--from the point of view of external code--as a heap object.

The only situation in which a value type's implementation of an interface may be used without the value type first being converted to a heap object is when it's passed as a generic type parameter which has the interface type as a constraint. In that particular situation, interface members may be used on the value type instance without its having to be converted to a heap object first.