在開發設計.Net時,MS所做的最聰明的修改之一就是他們意識到,如果沒有 辦法整合已經存在的代碼到新的.Net環境中,那沒沒有人會接受這個新的平台。 MS知道,如果沒有辦法來利用已經存在的代碼,這將阻止大家接受它。與其它非 托管代碼的交互是可以工作了,但這是可交互唯一可以拿來說一下的有利的地方 。對於所有的交互策略,當操作流程在本地代碼和托管代碼之間的邊界上進行傳 送時,都要求強制提供一些 編組的信號。同時,交互策略強迫開發人員必須手 動的申明所有調用參數(譯注:這裡是說你根本不知道參數的數據類型,很多時 間你都只能以int32的方式傳遞所有參數,例如文件句柄,字符串指針等幾乎是 所有的參數,都只有一個int32也就是IntPtr類型進行處理,當然這裡認為是是 在32位機器上。)。最後,CLR還不能完成對托管代碼和本地代碼的邊界上進行數 據傳遞時的優化。忽略采用本地代碼或者COM對象時得到的好處吧,沒有什麼比 這更好的了(譯注:我本人強烈反對這一原則。C++,COM在目前來說,絕對有它 生存的優勢,我覺得應該充分利用這些優勢,而不應該忽略它們)。但事實是交 互並不是總能工作的,很多時候我們還是在要已經存在的應用程序中添加新的功 能,提高而且更新已經存在的工具,或者在其它的地方要完成一個新的托管應用 程序與舊的應用程序交互。使用一些交互在實際應用中只會是減緩對舊系統的更 替。所以,有明白不同的交互策略之間有什麼開銷是很重要的。這些開銷要同時 花在開發計劃以及運行時性能中。有些,最後的選擇是重寫舊代碼。還有一些時 候,你須要選擇正確的交互策略。
在我討論這個對你有用的交互策略之 前,我須要花一段來討論放棄(just throw it out)策略。第五章,與.Net框架 一起工作,向你展示了一些.Net裡已經為你創建好了的類和技術,你可以直接使 用或者派生。為你你想的很多,你可以確定一些類和你一些代碼算法,並且全部 用C#重寫。剩下存在的代碼可以被.Net框架裡已經存在的可能功能性的派生來取 代。這並不會總是在任何地方,任何時候都可以工作的,但這確實是一個經過認 真考慮過的遷移策略。整個第5章都推薦使用"throw it out“策略。 這一原則就專注於交互,而它確實是件痛苦的事情。
接下來,讓我們假 設你已經決定重寫全部代碼並不實際。一些不同的策略要求你從.Net中訪問本地 代碼。你須要明白在本地代碼和托管代碼的邊界上傳遞數據時的開銷的低效。在 使用交互時有三個開銷。首先就是數據集群處理,這在托管堆和本地代碼堆之間 進行數據傳遞時發生。其次就是在托管代碼和非托管代碼進行交互時的大量數據 吞吐時的開銷。你以及你的用戶要承擔這些開銷。第三個開銷就只是你自己的了 :你要在這個混合的開發環境中添加很多工作來實現交互。這也是最糟糕的一個 ,所以你的設計應該決定最小化這樣的開銷。
讓我們開始討論交互時在 性能上的開銷,以及如何最小化這些開銷。數據集群是最大的一個因數,就像是 網絡服務或者遠程操作一樣,你須要盡可能使用笨重的(chunky)API而不是小巧 的(chatty )API(譯注:數據集群是指你沒有辦法即時的與本地代碼進行交互, 而有一個延時,這個延時就使用數據堆集起來一起處理,這樣就使得你應該盡可 能少的與本地代碼進行交互,而要選擇一些一次可以處理較多數據的API)。你可 以用不同的方法來完成與非托管代碼的交互。你可以重新修改已經存在的非托管 代碼來創建一個笨重的API,更適合交互的API。常規的COM應用中是申明很多屬 性,這樣客戶可以設置並修改COM對象內部的狀態或者行為。每次的設置屬性都 會集群數據,而且不得不穿越邊界。(而且每在穿越交互邊界時也會有thunks。) 這非常的低效,不幸的是,COM對象或者非托管庫可能不受你控制。當這種情況 發生時,你須要完成更麻煩的工作。這時,你可以創建一個輕量級的C++庫,通 過使用你所須要的chunkIEr API來暴露類型的功能。這就要增加你的開發時間了 (也就是第三個開銷)。
當你封裝一個COM對象時,確保你修改的數據類型 已經在本地代碼一托管代碼之間提供了最好的數據集群策略。有些類型可以很好 的比其它類型進行集群,試著限制用於在本地代碼和托管代碼之間進行傳遞的數 據類型,盡量使用blittable數據。blittable是指托管代碼和本地代碼都一樣使 用的類型。數據內容可以直接拷貝而不用管對象的內部的結構。某些情況下,非 托管代碼可能使用托管代碼的代碼。下面列出了blittable 類型:
System.Byte
System.SByte
System.Int16
System.UInt16
System.Int32
System.UInt32
System.Int64
System.UInt64
System.UIntPtr
另 外,任何的blittable類型的一維數組也是blittable類型。最後,任何格式化的 包含blittable類型的也是blittable類型。一個格式化的類型可以是一個用 StructLayoutAttribute明確定義了數據層次的結構,
[ StructLayout( LayoutKind.Sequential ) ]
public struct Point3D
{
public int X;
public int Y;
public int Z;
}