Does passing a struct into an interface field allocate?

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.


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 .


    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
    

    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.

    链接地址: http://www.djcxy.com/p/52834.html

    上一篇: Func <>委托有什么好处?

    下一篇: 是否将结构传递到接口字段分配?