2009-11-29 22 views
3

我有一個結構是這樣的是否將結構傳遞給接口字段分配?

struct MyStructure 
    :IFoo 
{ 
} 

和方法是這樣的:

public BarThisFoo(IFoo a) 
{ 

} 

我的問題是不經過結構納入法「盒子」結構,從而導致垃圾分配?

附錄: 在任何人說出它之前,垃圾收集在這個應用程序中不是免費的,它實際上對垃圾收集非常敏感,所以分配自由代碼非常重要。

+0

您可以輕鬆地避免裝箱,看到我的回答如下。 – 2009-11-29 23:31:08

+0

謝謝!我已經向作者提出了這個建議,他不太熱衷,但我可能會贏得他;) – Martin 2009-11-30 18:28:46

回答

4

是的,它的作用。拳擊每當你轉換從發生:

  • 值類型到一個對象引用
  • 值類型到System.ValueType參考
  • 值類型到一個參考由值類型實現的接口
  • 枚舉類型到System.Enum參考

這情況下III,很明顯。您可以閱讀更詳盡的示例here

1

是的。將值類型轉換爲符合的接口類型將填充值。爲了將值類型作爲對象處理,需要進行裝箱操作。它將必要的頭文件(包括vtable)添加到值中,以便您可以調用接口方法。盒裝值作爲任何管理對象都要經過垃圾收集。

5

正如其他人已經指出,是的,將一個結構轉換爲它實現的接口是一個拳擊演員。更重要的不是問題的答案是什麼,而是你能夠自己回答。如果使用ILDASM反彙編測試應用程序,則會看到「編譯器」指令是在編譯器轉換時生成的。現在下一次你有關於拳擊的問題,你可以寫一個測試程序,拆卸它,然後你就會知道。

順便說一句,注意,如果你調用一個方法上一個結構隱式實現的接口方法,拳擊不會發生:

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

這是對可變的值類型的接口方法尤爲重要;請記住,如果你正在改變盒裝值類型,那麼你在框中改變值,而不是最初包含盒裝值的變量。 myS.Foo()和((IFoo)myS).Foo()可以具有不同的語義這一事實是可變值類型爲純邪惡並應該避免的另一個原因。

+0

你說得對,我真的應該看看ILDASM的某個時候,我見過一些人使用它,但從來沒有(如果只有沒有世界短缺round-tooits);) – Martin 2009-11-30 08:45:48

+0

馬丁:ILDASM通常放在'開始菜單\程序\微軟Windows SDK v6.0A'文件夾:) – 2009-11-30 09:03:38

+0

有趣的是,它不是在那裏。我將不得不在晚些時候看看:/ – Martin 2009-11-30 18:26:35

7

爲了避免拳擊時,你可以使用泛型與約束:

struct MyStructure 
    :IFoo 
{ 
} 

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

} 

J. Richter CLR via C#,第2版,第14章:接口,節約泛型和接口約束。

編輯:

示例代碼

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代碼的方法主要不含任何盒說明:

.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 
+0

謝謝,這是我希望做的。不幸的是,代碼不是我的代碼,所以我必須說服原作者這是需要的。 – Martin 2009-11-30 08:43:30