本文基於 CLR 互操作團隊實戰經驗,系統闡述托管與非托管代碼互操作的適用場景、三大核心技術選型指南、架構設計決策要點、效能優化原則與生命週期管理難題解法。
過往指南常建議「重寫為托管代碼」,但對大型既有系統不切實際。互操作價值在於保護既有投資、同時享受托管優勢。三大典型應用:
對應三大動機:托管擴充性、混合開發、現代化 UI 注入。若單純為用新技術而重寫,不屬互操作範疇。
| 技術 | 適用場景 | 特性 |
|---|---|---|
| P/Invoke | 呼叫 C 風格非托管 API,API 數量少、簽名簡單 | 最簡單;參數複雜(變長結構、void*、union)時困難 |
| COM Interop | 既有 COM 介面、需完整 COM 語義、VB6 互操作 | 自動處理 COM 細節;效能與彈性受限 |
| C++/CLI | 需靜態型別檢查、極致效能、完全控制邊界 | 最強大;強制開發者承擔邊界控制責任;不適合寫應用主體 |

Office 以 COM 為擴充機制,早期依賴 TlbImp 薄型互操作組件,後隨 VSTO 內建提供豐富開發模型,但底層仍基於 COM Interop。
/clr 編譯,核心功能用純托管/純非托管組件組合自問:誰寫互操作層?優化其體驗還是最小化建構成本?開發者是內部團隊還是第三方?技術水準如何?願意碰非托管模式嗎?
核心原則:減少轉換次數、減少跨邊界資料量。固定成本由技術決定,優化重點在邊界設計。
難題 1:非托管資源被托管物件長期佔用
稀缺資源(資料庫連線)需及時釋放。解法:為非托管物件加薄封裝實作 IDisposable,標準 Dispose 模式,托管代碼显式釋放。
難題 2:垃圾收集器感知不到非托管記憶體壓力
大量小型托管封裝持有巨大非托管結構 → GC 僅見釋放少量托管記憶體 → 收集頻率降低 → 記憶體持續增長。
解法:.NET 2.0 新增 GC.AddMemoryPressure / RemoveMemoryPressure,在封裝建構式與完成項中呼叫,告知 GC 真實非托管記憶體成本。
難題 3:組件卸載差異
非托管庫可卸載,托管組件需卸載 AppDomain。構建非托管宿主載入托管增益集時,為每個增益集使用獨立 AppDomain,獲得等同卸載非托管庫的彈性。
互操作非萬能藥,但在保護既有資產、漸進式現代化路上是關鍵橋樑。技術選型決於 API 型態與邊界控制需求;架構成敗在於邊界設計、效能覺察與生命週期管理的嚴謹落實。