共用方式為


複製和釘選

封送處理數據時,Interop 封送處理器可以複製或釘選正在封送處理的數據。 複製數據會將數據複本從某個記憶體位置放在另一個記憶體位置。 下圖顯示複製實值型別與從 Managed 到 Unmanaged 記憶體之間複製以傳址方式傳遞的類型之間的差異。

顯示如何複製值和參考型別的圖表。

以值傳遞的函式參數會封送處理至非受控程式碼,作為堆疊上的值。 複製過程是直接的。 以參考傳遞的參數會作為堆疊上的指標傳遞。 參考型別也可以透過傳值或傳址的方式傳遞。 如下所示,傳值傳遞的引用類型會複製或釘選:

顯示以傳值和傳址方式傳遞之參考型別的圖表。

固定會暫時鎖定資料在其目前的記憶體位置,進而防止其被 Common Language Runtime 的垃圾收集器重新安置。 封送器會固定資料,以減少複製運算負擔並增強效能。 數據類型會決定在封送處理過程中是複製還是鎖定。 在封送處理期間,物件(例如 String)的記憶體固定會自動執行,但您也可以使用 GCHandle 類別手動固定記憶體。

格式化的 Blittable 類別

格式化的 blittable 類別在管理和非管理記憶體中都有固定的版面配置(格式化)和通用數據表示法。 當這些類型需要封送處理時,堆積中物件的指標會直接傳遞至被呼叫者。 被呼叫者可以變更指標所參考之內存位置的內容。

備註

如果參數標示為 Out 或 In/Out,被呼叫者可以變更記憶體內容。相反地,當參數設為以 In 進行封送處理時,被呼叫者應避免變更內容,這是格式化 blittable 類型的預設設定。 修改 In 物件會在將相同類別匯出至類型連結庫並用來進行跨 Apartment 呼叫時產生問題。

格式化的Non-Blittable類別

格式化的非 blittable類別具有固定的版面配置(已格式化),但資料在受控與非受控記憶體中的呈現方式不同。 在下列情況下,數據可能需要轉換:

  • 如果非 blittable 類別是以值類型的方式封送處理,被呼叫者會收到數據結構複本的指针。

  • 如果非 blittable 類別是以傳址方式封送處理,被呼叫者會收到數據結構複本指標的指標。

  • 如果設定了InAttribute屬性,此副本會始終使用實例的狀態初始化,並在必要時進行封送處理。

  • 如果設定了OutAttribute屬性,則狀態一律會在傳回時複製回實例,並視需要進行封送處理。

  • InAttributeOutAttribute 均已設定,則需取得兩份副本。 如果省略任一個屬性,封送處理器可以透過排除其中一個副本來進行優化。

參考型別

參考型別可以透過值或參考來傳遞。 當它們以值傳遞方式傳遞時,型別的指標會被放在堆疊上傳遞。 以參考方式傳遞時,會在堆疊上傳遞指向類型指標的指標。

參考型別具有下列條件式行為:

  • 如果參考型別是以傳值方式傳遞,且具有非 blittable 型別的成員,那麼其類型將被轉換兩次。

    • 當自變數傳遞至 Unmanaged 端時。

    • 呼叫結束後。

    為了避免不必要的複製和轉換,這些類型會被處理作為 In 參數。 你必須明確將 InAttributeOutAttribute 屬性應用到參數中,以便呼叫者可以看到被呼叫者所做的更改。

  • 如果參考型別是以傳值方式傳遞,而且只有 blittable 型別的成員,則可以在封送處理期間釘選它,而且呼叫端會看到對型別成員所做的任何變更。 如果你想要這種行為,就要明確地套用InAttributeOutAttribute。 如果沒有這些方向屬性,Interop 封送處理器就不會將方向資訊匯出至類型庫(其匯出為 In,這是預設值),這可能會導致 COM 跨 Apartment 封送處理的問題。

  • 如果參考型別是以傳址方式傳遞,則預設會封送為 In/Out。

System.String 和 System.Text.StringBuilder

當數據以值或參考方式封送至非受控程式碼時,封送器通常會將數據複製到次要緩衝區(可能在複製期間轉換字元集),並將緩衝區的參考傳遞給被呼叫者。 除非參考是 BSTRSysAllocString 配置的,否則該參考總是以 CoTaskMemAlloc 配置。

StringStringBuilder以值形式封送處理(例如 Unicode 字元串)時,作為一種優化,封送器會將內部 Unicode 緩衝區中的 managed 字串的直接指標傳遞給被呼叫方,而不是將其複製到新的緩衝區。

謹慎

當字串以值傳遞時,被呼叫者絕不能改變封送器所傳遞的參考。 這樣做可能會損毀受控堆積。

System.String以傳址方式傳遞 時,封送器會在進行呼叫之前,先將字串的內容複製到次要緩衝區。 然後,它會在呼叫傳回時,將緩衝區的內容複製到新的字串中。 這項技術可確保不可變的Managed字串保持不變。

當以傳值方式傳遞System.Text.StringBuilder時,封送處理器會將StringBuilder內部緩衝區的臨時副本的參考傳給呼叫者。 呼叫端和被呼叫者必須同意緩衝區的大小。 呼叫者負責製作足夠長度的訊息 StringBuilder 。 被呼叫者必須採取必要的預防措施,以確保緩衝區不會發生溢位。 StringBuilder 是對於參考型別預設以值傳遞為 In 參數這項規則的例外。 StringBuilder 一律傳遞為 In/Out

另請參閱