views:

177

answers:

5

I have a structure something like this

struct MyStructure
    :IFoo
{
}

and a method like this:

public BarThisFoo(IFoo a)
{

}

my question is does passing the structure into that method "box" the structure, thus causing a garbage allocation?

Addendum: Before anyone says it, garbage collection is not free in this application, it's actually very sensitive to garbage collections, so allocation free code is important.

+1  A: 

Yes. Casting a value type to an interface type it conforms to will box the value. Boxing operation is required in order to treat the value type as an object. It adds the necessary headers (incl. vtable) to the value so that you can call interface methods on it. A boxed value is subject to garbage collection as any managed object.

Mehrdad Afshari
+1  A: 

Boxing is the process of converting a value type to the type object or to any interface type implemented by this value type.

Source: http://msdn.microsoft.com/en-us/library/yz2be5wk.aspx

Mark Byers
+4  A: 

Yes, it does. Boxing occurs whenever you convert from:

  • a value type to an object reference
  • a value type to a System.ValueType reference
  • a value type to a reference to an interface implemented by the value type
  • an enum type to a System.Enum reference

This is case III, obviously. You can read a more thorough example here.

John Feminella
+5  A: 

As others have noted, yes, converting a struct to an interface it implements is a boxing cast. More important is not what the answer to the question is, but that you be able to answer it yourself. If you use ILDASM to disassemble a test application, you'll see that the "box" instruction is generated by the compiler at the point of the conversion. Now next time you have a question about boxing, you can just write yourself a test program, disassemble it, and then you'll know.

Incidentally, note that boxing does NOT happen if you call a method on an implicitly implemented interface method on a struct:

struct S : IFoo { public void Foo() { ... 
...
myS.Foo(); // no boxing
((IFoo)myS).Foo(); // boxing

This is particularly relevant for interface methods on mutable value types; remember, if you're mutating a boxed value type then you're mutating the value in the box, not the variable that originally contained the boxed value. The fact that myS.Foo() and ((IFoo)myS).Foo() can have different semantics is yet another reason why mutable value types are pure evil and should be avoided.

Eric Lippert
You're right, I really should have a look into ILDASM sometime, I've seen a few people using it but have never got around to it (if only there wasn't a world shortage of round-tooits) ;)
Martin
Martin: ILDASM is usually placed in 'Start Menu\Programs\Microsoft Windows SDK v6.0A' folder :)
Roman Boiko
Interestingly, it's not there. I'll have to look into it later :/
Martin
+5  A: 

To avoid boxing you can use generics with constraints:

struct MyStructure
    :IFoo
{
}

public void BarThisFoo<T>(T a) where T : IFoo
{

}

See J. Richter CLR via C#, 2nd edition, chapter 14: Interfaces, section about Generics and Interface Constraints.

EDIT:

Example code

using System;
using System.Collections;

interface IFoo {
    void Foo();
}
struct MyStructure : IFoo {
    public void Foo() {
    }
}
public static class Program {
    static void BarThisFoo<T>(T t) where T : IFoo {
        t.Foo();
    }
    static void Main(string[] args) {
        MyStructure s = new MyStructure();
        BarThisFoo(s);
    }
}

IL code for method Main doesn't contain any box instructions:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       15 (0xf)
  .maxstack  1
  .locals init ([0] valuetype MyStructure s)
  IL_0000:  ldloca.s   s
  IL_0002:  initobj    MyStructure
  IL_0008:  ldloc.0
  IL_0009:  call       void Program::BarThisFoo<valuetype MyStructure>(!!0)
  IL_000e:  ret
} // end of method Program::Main
Roman Boiko
Thanks, this is what I hope to do. Unfortunately the code isn't my code so I have to persuade the original author this is needed.
Martin