将结构传递给接口字段是否分配?

Mar*_*tin 3 c# garbage-collection

我有一个像这样的结构

struct MyStructure
    :IFoo
{
}
Run Code Online (Sandbox Code Playgroud)

和这样的方法:

public BarThisFoo(IFoo a)
{

}
Run Code Online (Sandbox Code Playgroud)

我的问题是将结构传递给该方法的"框"结构,从而导致垃圾分配?

附录:在有人说之前,垃圾收集在这个应用程序中不是免费的,它实际上对垃圾收集非常敏感,所以免费分配代码很重要.

Rom*_*iko 8

为了避免装箱你可以使用带有约束的泛型:

struct MyStructure
    :IFoo
{
}

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

}
Run Code Online (Sandbox Code Playgroud)

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

编辑:

示例代码

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

方法Main的IL代码不包含任何框指令:

.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
Run Code Online (Sandbox Code Playgroud)


Joh*_*lla 5

是的,它确实.每当你转换时都会发生拳击:

  • 对象引用的值类型
  • System.ValueType引用的值类型
  • 值类型,用于引用由值类型实现的接口
  • System.Enum引用的枚举类型

显然,这是案例III.您可以在此处阅读更全面的示例.


Eri*_*ert 5

正如其他人已经注意到的那样,是的,将结构体转换为它实现的界面是拳击模型.更重要的不是问题的答案,而是你能够自己回答.如果使用ILDASM反汇编测试应用程序,您将看到编译器在转换时生成"box"指令.现在下次你有关于拳击的问题,你可以自己写一个测试程序,反汇编,然后你就会知道.

顺便提一下,请注意,如果在结构上的隐式实现的接口方法上调用方法,则不会发生装箱:

struct S : IFoo { public void Foo() { ... 
...
myS.Foo(); // no boxing
((IFoo)myS).Foo(); // boxing
Run Code Online (Sandbox Code Playgroud)

这与可变值类型的接口方法特别相关; 请记住,如果您正在改变盒装值类型,那么您正在改变框中的值,而不是最初包含盒装值的变量.myS.Foo()和((IFoo)myS).Foo()可以有不同的语义这一事实是可变值类型纯粹是邪恶的另一个原因,应该避免.