今天看到一段介紹C#實現代理模式的代碼,使用到了MarshalByRefObject。那麼MarshalByRefObject到底是什麼東西呢?簡單來講,繼承此類的對象可以跨越應用程式定義域邊界被引用,甚至被遠端參照。遠程調用時,將產生一個遠程對象在本地的透明代理,通過此代理來進行遠程調用。一篇很好的解釋文章,來自http://dudu.cnblogs.com/archive/2004/03/04/2182.html
問:<o:p>
打擾一下,請問MarshalByRefObject中的"Marshal"應該怎樣理解?<o:p>
<o:p> </o:p>
回複:
按照package的意思理解——當一個對象需要長途跋涉到另一個環境中時,需要將其marshal成一個可以傳輸的形態(比如在.NET Remoting中對象將被打包成一個serializable的ObjRef執行個體——這個ByRef就是指ObjRef這種形態);同理,當打包以後傳輸到目標地點,還要執行unmarshal的操作將其還原為記憶體中的對象。:)<o:p>
<o:p> </o:p>
問:<o:p>
謝謝!<o:p>
MarshalByRefObject是不是可以這樣理解:對被引用的對象進行Marshal。如果按照package的意思理解,那package的過程是怎樣的?<o:p>
<o:p>
MSDN上這樣講:<o:p>
MarshalByRefObject是通過使用代理交換訊息來跨應用程式定義域邊界進行通訊的對象的基類.<o:p>
MarshalByRefObject對象在本地應用程式定義域的邊界內可直接存取。遠程應用程式定義域中的應用程式首次訪問MarshalByRefObject時,會向該遠程應用程式傳遞代理。對該代理後面的調用將封送回駐留在本地應用程式定義域中的對象。<o:p>
<o:p>
在Marshal中,上面所說的代理是什嗎?有什麼用?<o:p>
<o:p>
MSDN上還講到:<o:p>
當跨應用程式定義域邊界使用類型時,類型必須是從MarshalByRefObject繼承的,而且由於對象的成員在建立它們的應用程式定義域之外無法使用,所以不得複製對象的狀態。<o:p>
<o:p>
既然對象的狀態不能傳遞過去,那傳遞這個對象又有何意義?<o:p>
第一次去理解MarshalByRefObject,有的問題可能提的比較膚淺,請您指點。<o:p>
<o:p> </o:p>
回複:<o:p>
MarshalByRefObject是所有可以在AppDomain邊界外部存取的對象的基類,重心不是marshal,而是object,即object that could be marshaled by reference,也就是可以通過Ref(實際上是ObjRef對象)的機制進行“封送”(MSDN中文版對marshal一詞的翻譯)的對象。封送的行為是由代理來做的,這裡說的代理就是我文章中講過的.NET Remoting的真實代理(即RemotingProxy)。真實代理不是有一個Invoke()方法嗎?當你透過對一個MBRO的透明代理訪問該對象的方法時,透明代理將把基於堆棧的方法調用轉換為方法調用訊息(IMethodCallMessage)並轉寄給真實代理(在Remoting的場合中也即RemotingProxy),而RemotingProxy的任務就是把對象封送並連同方法調用訊息一起轉寄給遠程應用程式定義域;到達目的地以後的操作類似:遠程應用程式定義域中的監聽方當收到發來的方法調用訊息時,先取出封送好的ObjRef(這個對象裡面儲存著發來調用的那個對象!),將其結封(unmarshal)為本地的對象,並獲得其透明代理,然後就可以把方法調用訊息在轉換回基於堆棧的調用發送給這個對象。<o:p>
<o:p>
對象是在本地維護的,但是方法可以在遠程調用。你比如說一個web應用程式,你是通過本地的瀏覽器遠端存取這個應用程式,但是應用程式的狀態不會由你的瀏覽器負責(所以你只是在訪問這個應用程式提供給你的功能而已,你並沒於擁有應用程式本身,包括其所有資料),你只是發送一個個的請求,伺服器告訴你處理的結果。在Remoting中 也是一樣,當你獲得一個遠程對象的時候,你實際上只擁有對這個對象的一個遠端參照,雖然你可以調用它的方法,但實際上這些操作都是發生在遠端(就是前面 講過的過程),你只是傳入了一些參數,得到了一個結果,但對象的狀態還是在遠程維護的(換句話說,對象本身也就是對象的所有狀態並沒有被往返傳遞,傳遞的 只是傳入傳出的參數——當然,如果參數是一個MBRO的話,還是傳遞對象被封送的引用)。 <o:p>
也許應該給你準備一個好理解的例子……你就會豁然開朗了。:)<o:p>
<o:p> </o:p>
問:<o:p>
我這樣的理解對不對?<o:p>
一般的對象與從MarshalByRefObject繼承的對象區別是:<o:p>
一般的對象只能在本地應用程式定義域之內被引用,而MarshalByRefObject對象可以跨越應用程式定義域邊界被引用,甚至被遠端參照。<o:p>
<o:p> </o:p>
回複:
Exactly! 當對象跨出AppDomain邊界的時候,實際上只是它的一個引用(ObjRef)。你比如說吧:<o:p>
<o:p>
public class LocalObject
{<o:p>
public void CallRemoteObject(MarshalByRefObject mbro)
{
Console.WriteLine(mbro.ToString());<o:p>
}
}<o:p>
<o:p>
當傳入一個在本地建立的mbro對象時,ToString()方法是直接發送給對象的;而當mbro是通過Remoting建立的遠程對象的話,實際上它只是一個包含有已經marshal好的ObjRef的透明代理,ObjRef裡面有什嗎?對象執行個體的URI!所以當你調用這個遠程對象時,相當於向這個遠程連接埠(tcp://remoteServer/xxxx.rem)發送方法調用訊息而已。只不過透明代理隱藏了對象位置的概念,而RemotingProxy真實代理則是實際上處理遠程方法調用和對象封送的中樞對象。