tags:

views:

478

answers:

2

Hello,

I have the following simple C# code:

private Stack<Person> m_stack = new Stack<Person>();

public void Add<T>(T obj)
  where T : Person
{
     m_stack.Push(obj);
}

This will produce the following IL code:

  .method public hidebysig instance void 
          Add<(ConsoleApplication1.Person) T>(!!T obj) cil managed
  {
    // Code size       20 (0x14)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldarg.0
    IL_0002:  ldfld      class [System]System.Collections.Generic.Stack`1<class ConsoleApplication1.Person> ConsoleApplication1.Pool::m_stack
    IL_0007:  ldarg.1
    IL_0008:  box        !!T
    IL_000d:  callvirt   instance void class [System]System.Collections.Generic.Stack`1<class ConsoleApplication1.Person>::Push(!0)
    IL_0012:  nop
    IL_0013:  ret
  } // end of method Pool::Add

So my question is... why boxing? (IL_0008) I can understand downcasting or even compile error, but why boxing (Person is a reference type...)

Thanks in advance!

+4  A: 

I believe it's the generic method constraint that does this to you - but...

In any case, there's no need for the generic method at all. Just write it as:

public void Add(Person person)
{
    m_stack.Push(person);
}

You'll find that the IL gets simplified, and completely avoids the issue. If you're constraining to a specific reference type, you can just use that reference type.

This is much easier to understand, and much more clear. I'd suggest avoiding the generic method call unless it's really needed. Generic methods make the class less obvious, which means less readable and maintainable in the long run, and more difficult to use.

Reed Copsey
@ Reed: Yeah, this is how I solved the problem, but I was curious why the reference type is boxed (doesn't make any sense)...
I think it's an implementation of how generic methods work. Notice that it's boxing T, not Person. You're never boxing/unboxing your class, but it's something "extra" that ends up in there in generic method calls. Not sure why, though.
Reed Copsey
+25  A: 

Excerpt from Ecma-335 Partition III 4.1

If typeTok is a reference type, the box instruction does nothing.

where typeTok is !!T in your case.

My guess is that when the compiler compiles the code, it always calls box regardless whether the type of the operand is reference type or not. Because of the semantic of the box instruction, the desired result is always guaranteed.

ruiyiz
this is the correct answer.
JaredPar
+1 Nice job tracking this down. Good information. Would this instruction get removed by the JIT too, then, or does it cause a noop instruction to be left in place?
Reed Copsey