對MarshalByRefObject的解釋
今天看到一段介紹C#實現代理模式的代碼,使用到了MarshalByRefObject。那麼MarshalByRefObject到底是什麼東西呢?簡單來講,繼承此類的對象可以跨越應用程序域邊界被引用,甚至被遠程引用。遠程調用時,將產生一個遠程對象在本地的透明代理,通過此代理來進行遠程調用。一篇很好的解釋文章,來自https://dudu.cnblogs.com/archive/2004/03/04/2182.html問:
打擾一下,請問MarshalByRefObject中的"Marshal"應該怎樣理解?
回複:
按照package的意思理解——當一個對象需要長途跋涉到另一個環境中時,需要將其marshal成一個可以傳輸的形態(比如在.NET Remoting中對象將被打包成一個serializable的ObjRef實例——這個ByRef就是指ObjRef這種形態);同理,當打包以後傳輸到目標地點,還要執行unmarshal的操作將其還原為內存中的對象。:)
問:
謝謝!
MarshalByRefObject是不是可以這樣理解:對被引用的對象進行Marshal。如果按照package的意思理解,那package的過程是怎樣的?
MSDN上這樣講:
MarshalByRefObject是通過使用代理交換消息來跨應用程序域邊界進行通訊的對象的基類.
MarshalByRefObject對象在本地應用程序域的邊界內可直接訪問。遠程應用程序域中的應用程序首次訪問MarshalByRefObject時,會向該遠程應用程序傳遞代理。對該代理後麵的調用將封送回駐留在本地應用程序域中的對象。
在Marshal中,上麵所說的代理是什麼?有什麼用?
MSDN上還講到:
當跨應用程序域邊界使用類型時,類型必須是從MarshalByRefObject繼承的,而且由於對象的成員在創建它們的應用程序域之外無法使用,所以不得複製對象的狀態。
既然對象的狀態不能傳遞過去,那傳遞這個對象又有何意義?
第一次去理解MarshalByRefObject,有的問題可能提的比較膚淺,請您指點。
回複:
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)為本地的對象,並獲得其透明代理,然後就可以把方法調用消息在轉換回基於堆棧的調用發送給這個對象。
對象是在本地維護的,但是方法可以在遠程調用。你比如說一個web應用程序,你是通過本地的瀏覽器遠程訪問這個應用程序,但是應用程序的狀態不會由你的瀏覽器負責(所以你隻是在訪問這個應用程序提供給你的功能而已,你並沒於擁有應用程序本身,包括其所有數據),你隻是發送一個個的請求,服務器告訴你處理的結果。在Remoting中 也是一樣,當你獲得一個遠程對象的時候,你實際上隻擁有對這個對象的一個遠程引用,雖然你可以調用它的方法,但實際上這些操作都是發生在遠程的(就是前麵 講過的過程),你隻是傳入了一些參數,得到了一個結果,但對象的狀態還是在遠程維護的(換句話說,對象本身也就是對象的所有狀態並沒有被往返傳遞,傳遞的 隻是傳入傳出的參數——當然,如果參數是一個MBRO的話,還是傳遞對象被封送的引用)。
也許應該給你準備一個好理解的例子……你就會豁然開朗了。:)
問:
我這樣的理解對不對?
一般的對象與從MarshalByRefObject繼承的對象區別是:
一般的對象隻能在本地應用程序域之內被引用,而MarshalByRefObject對象可以跨越應用程序域邊界被引用,甚至被遠程引用。
回複:
Exactly! 當對象跨出AppDomain邊界的時候,實際上隻是它的一個引用(ObjRef)。你比如說吧:
public class LocalObject
{
public void CallRemoteObject(MarshalByRefObject mbro)
{
Console.WriteLine(mbro.ToString());
}
}
最後更新:2017-05-17 12:02:07