共用方式為


Boxed 值的追蹤控制代碼

從 Managed Extensions for C++ 升級為 Visual C++ 之後,使用追蹤控制代碼 (Tracking Handle) 參考實值型別 (Value Type) 的方式已變更。

Boxing 是 CLR 統一型別系統的一項特性。 實值型別會直接包含其狀態,而參考型別 (Reference Type) 則會採用隱含搭配方式:具名實體 (Named Entity) 是在 Managed 堆積上配置之未命名物件的控制代碼。 例如,將實值型別初始化或指派給 Object 時,必須將實值型別放在 CLR 堆積中 (即其引發 Boxing 映像的所在位置),方式是先配置相關聯的記憶體,接著再複製實值型別的狀態,然後傳回此匿名值/參考組合的位址。 因此,當使用者在 C# 中撰寫下列程式碼時:

object o = 1024; // C# implicit boxing

雖然程式碼表面看起來很簡單,但實際的執行過程要複雜許多。 C# 的設計不僅會隱藏實際執行的作業,也會隱藏 Boxing 本身的抽取作業,因此看起來不會那麼複雜。 相反地,Managed Extensions for C++ 因為擔心這會造成使用者對效率的誤解,因此會要求使用者使用明確的指令:

Object *o = __box( 1024 ); // Managed Extensions explicit boxing

Boxing 在 Visual C++ 中為隱含:

Object ^o = 1024; // new syntax implicit boxing

在 Managed Extensions 中,__box 關鍵字是做為不可或缺的服務,這是 C# 和 Visual Basic 等語言在設計時所缺少的服務:它可以提供在 Managed 堆積上直接操作 Boxed 執行個體 (Instance) 所需的詞彙和追蹤控制代碼。 例如,以下列這一小段程式為例:

int main() {
   double result = 3.14159;
   __box double * br = __box( result );

   result = 2.7; 
   *br = 2.17;   
   Object * o = br;

   Console::WriteLine( S"result :: {0}", result.ToString() ) ;
   Console::WriteLine( S"result :: {0}", __box(result) ) ;
   Console::WriteLine( S"result :: {0}", br );
}

針對 WriteLine 的三個引動過程所產生的基礎程式碼,會顯示存取 Boxed 實值型別值時的不同負擔 (感謝 Yves Dolce 指出這些差異),其中所指的幾行會分別顯示與各引動過程相關聯的負擔。

// Console::WriteLine( S"result :: {0}", result.ToString() ) ;
ldstr      "result :: {0}"
ldloca.s   result  // ToString overhead
call       instance string  [mscorlib]System.Double::ToString()  // ToString overhead
call       void [mscorlib]System.Console::WriteLine(string, object)

// Console::WriteLine( S"result :: {0}", __box(result) ) ;
Ldstr    " result :: {0}"
ldloc.0
box    [mscorlib]System.Double // box overhead
call    void [mscorlib]System.Console::WriteLine(string, object)


// Console::WriteLine( S"result :: {0}", br );
ldstr    "result :: {0}"
ldloc.0
call     void [mscorlib]System.Console::WriteLine(string, object)

如果將 Boxed 實值型別直接傳遞至 Console::WriteLine,就可以排除 Boxing 處理,而且不需要叫用 (Invoke) ToString() (當然,之前初始化 br 時已有 Boxing 處理,因此除非真的使用 br,否則不會有任何作用)。

在新的語法中,Boxed 實值型別的支援更加簡潔,而且已整合到型別系統中,同時保留了原有的功能。 例如,下列就是前面那一小段程式的轉譯結果:

int main()
{
   double result = 3.14159;
   double^ br = result;
   result = 2.7;
   *br = 2.17;
   Object^ o = br;
   Console::WriteLine( "result :: {0}", result.ToString() );
   Console::WriteLine( "result :: {0}", result );
   Console::WriteLine( "result :: {0}", br );
}

請參閱

工作

How to: Boxing 來明確要求

概念

實值型別和行為 (C++/CLI)