可遠端處理和不可遠端處理的物件
請務必記住,雖然您可直接從應用程式定義域呼叫在該定義域中建立的物件 (因此是該定義域特有的),但若要在物件的定義域外部使用該物件,則必須先執行一些較特別的動作。並不是每個型別的物件都可以有效地跨定義域界限發行或取用;因此,您必須依據應用程式的需求,決定想要發行的物件型別。對於分散式應用程式而言,有兩種簡單的物件簡單兩類:不可遠端處理的物件和可遠端處理的物件。
不可遠端處理的物件
有些物件無法離開它們的應用程式定義域;因為它們未宣告序列化的方法,所以永遠不會對它們進行封送處理。這些不可遠端處理的物件是設計為在建立它們的相同應用程式定義域內使用,而且必須直接從該應用程式定義域存取。.NET Framework 類別庫中的大部分基底類別都是不可遠端處理的物件。您無法在另一個應用程式定義域中複製或表示不可遠端處理的物件。這些物件只可從原始的應用程式定義域存取。
可遠端處理的物件
可遠端處理物件可以使用 Proxy 從應用程式定義域或內容外的地方存取,或是複製並傳送到應用程式定義域或內容以外的地方;也就是說,有些可遠端處理的物件是以傳址方式傳遞,有些則以傳值方式傳遞。
可遠端處理的物件是可在廣泛分散式環境中正常運作的物件。可遠端處理的物件主要有兩種:
Marshal-by-value 物件,會從應用程式定義域複製並傳遞這些物件。
Marshal-by-reference 物件,用戶端會建立並使用 Proxy 以遠端存取這些物件。
Marshal-By-Value 物件
Marshal-by-value (MBV) 物件會宣告它們的序列化規則 (透過實作 ISerializable 以實作自己的序列化,或使用 SerializableAttribute 以告知系統要自動序列化物件),但不擴充 MarshalByRefObject。遠端處理系統會建立這些物件的完整複本,並將複本傳遞至呼叫應用程式定義域。一旦複本在呼叫端的應用程式定義域中,複本呼叫就會直接前往該複本。此外,當做引數傳遞的 MBV 物件也會以傳值方式傳遞。除了宣告 SerializableAttribute 屬性或實作 ISerializable 外,您並不需要進行其他處理,即可以傳值方式來跨應用程式或內容界限傳遞類別的執行個體。
![]() |
---|
從 .NET Framework 1.1 版開始,遠端處理基礎結構不會在伺服器上自動還原序列化特定的型別。如果您的案例也是這樣,則必須先將伺服器還原序列化層級設定為 Full,伺服器才能還原序列化並使用您的 MBV 物件。如需詳細資訊,請參閱 .NET 遠端處理中的自動還原序列化。 |
因效能或處理原因,而需要將物件完整狀態和任何可執行功能移動至目標應用程式定義域時,請使用 MBV 物件。在許多案例中,這個物件可減少在網路、處理序和應用程式定義域界限間耗時又耗資源的往返作業。 MBV 物件也可直接在該物件的原始應用程式定義域內使用。在這種情況下,因為不會發生任何封送處理,所以不會建立任何複本,且存取十分有效率。
相反的,如果發行的物件非常大,則在忙碌的網路中傳遞整個複本,對您的應用程式而言可能不是一個好方法。此外,所複製物件上發生的狀態變更永遠不會傳回原始應用程式定義域中的原始物件。在抽象層級上,這個案例與用戶端瀏覽器要求的靜態 HTML 網頁類似。伺服器會複製檔案、將它寫入資料流、送出它,然後就忘記它的存在。任何後續要求都只是對另一個複本的另一項要求。
除非是擴充已實作 ISerializable 的類別,否則您必須使用 SerializableAttribute 建立 marshal-by-value 型別。在這種情況下,您必須針對您的型別實作 ISerializable。
遠端處理系統會大量使用可序列化的物件。對另一個應用程式定義域中之物件的參考 (在遠端處理系統中以 ObjRef 類別表示) 本身是可序列化的;必須可完全複製它,並將複本傳送至要求。因為訊息物件是呼叫資料和其他任何必要物件參考的泛型容器,所以它們會實作 IMessage。此外,只傳輸資料的物件通常也是可序列化的物件。例如,DataSet 會擴充 MarshalByValueComponent,而後者會實作 ISerializable。
遠端處理使用者定義的例外狀況
系統定義的例外狀況全都是 marshal-by-value 型別 (它們會實作 ISerializable 介面),當遠端物件擲回這些型別的執行個體時,如果遠端處理組態允許,這些執行個體會自動複製至呼叫端 (從 .NET Framework 1.1 版開始,<customErrors> 項目必須設定為 off,例外狀況才能流向呼叫端)。
如需如何建立遠端物件可擲回而遠端呼叫端可攔截之例外狀況類型的詳細資訊,請參閱 如何建立遠端物件可擲回的例外狀況類型。
Marshal-By-Reference 物件
Marshal-by-reference (MBR) 物件是會至少擴充 System.MarshalByRefObject 的可遠端處理物件。依據所宣告的啟動型別而定,當用戶端在自己的應用程式定義域中建立 MBR 物件的執行個體時,.NET 遠端處理基礎結構會在呼叫端的應用程式定義域中建立表示該 MBR 物件的 Proxy 物件,並將該 Proxy 的參考傳回給呼叫端。然後,用戶端便會在該 Proxy 上進行呼叫。遠端處理會封送處理這些呼叫、將它們傳回給原始應用程式定義域,並在實際物件上叫用呼叫。
![]() |
---|
如果用戶端位在與 MBR 物件相同的應用程式定義域中,則基礎結構會將 MBR 物件的直接參考傳回給用戶端,因而省去封送處理的負擔。 |
如果將 MarshalByRefObject 當做參數傳遞,則當呼叫到達時,此物件會變成另一個應用程式定義域中的 Proxy。MBR 傳回值和 out 參數都是以相同方式運作。
![]() |
---|
從 .NET Framework 1.1 版開始,遠端處理基礎結構不會在伺服器上自動還原序列化特定的型別。例如,若要取得將 MBR 物件當做參數傳遞的支援,則必須先將伺服器的還原序列化層級設定為 Full,伺服器才能還原序列化並使用 MBR 參數。如需詳細資訊,請參閱 .NET 遠端處理中的自動還原序列化。 |
如果物件的狀態和任何可執行功能都應保留在建立該物件的應用程式定義域中,請使用 MBR 物件。例如,因為作業系統控制代碼在另一個應用程式定義域、處理序或電腦中不具任何意義,所以具有內部欄位來保存作業系統控制代碼的物件應該要擴充 MarshalByRefObject。有時,物件也會過大;在穩固的伺服器上,該物件或許可以運作,但透過 Wire 傳送至 33.6 KBps 數據機時,就會發生問題。
內容繫結物件
內容繫結物件是繼承自 System.ContextBoundObject (此物件又繼承自 System.MarshalByRefObject) 的 MBR 物件。您可將內容想成應用程式定義域的子區塊,這個子區塊為位在其中的物件提供豐富的執行環境。例如,內容可保證不會有多個執行緒同時存取物件。每個應用程式定義域都有預設的內容。大部分的 Managed 程式碼會使用同一應用程式定義域的預設內容直接建立物件,並從該定義域內呼叫成員,而不會發生任何內容相關的問題。所有繼承自 ContextBoundObject 的型別都會公開給其他內容 (位在同一定義域或其他定義域的內容) 做為 Proxy。
例如,假設有個方法位於屬於交易一部分的型別上,因此由建立它時所在內容的特定規則所繫結。該型別應該要繼承自 ContextBoundObject,以便從專屬的內容來存取物件,而系統也可以強制執行與該物件和其方法相關之交易有關的規則。如果是從同一應用程式定義域內的另一個內容呼叫 ContextBoundObject,則會為該呼叫端建立 Proxy,但不會透過通道系統進行內容間通訊,這種情況下,呼叫效率會增加。
因為跨越每個界限都需要處理時間,所以在決定您的伺服器屬於哪一種可遠端處理物件型別之前,應該先決定物件必須跨越的界限。特定內容特有的物件只能直接從該內容存取。這對特定應用程式定義域特有的物件也是一樣。若要遠端處理任一物件,遠端處理系統必須先順利跨越內容界限或 (及) 應用程式界限,才能從伺服器物件所在的任何界限內叫用該伺服器物件。如果您不需要進行內容檢查即呼叫物件,則不應讓遠端型別擴充 ContextBoundObject;MarshalByRefObject 的執行效果會更好。如果您需要進行內容檢查,則應擴充 ContextBoundObject,但應該要瞭解,您必須先跨越其他界限,才能在物件上進行呼叫。
發行範圍
不同的遠端處理系統會有不同的方法,來決定可遠端使用的成員和成員型別。.NET 遠端處理會將物件如區域物件般地公開給其他應用程式定義域,但有下列例外:
靜態成員。
絕不會遠端處理靜態欄位和方法,而欄位也是透過直接記憶體存取。也就是說,.NET 遠端處理會固定處理某種形式的執行個體成員。
執行個體欄位和存取子。
若為執行個體欄位和存取子方法,則系統會在執行階段插入檢查,以判斷物件是否為 Proxy。如果不是 Proxy,則會直接存取欄位。否則,Proxy 會將存取子提供給呼叫端。
私用方法。
無法遠端處理私用方法。您無法將委派包裝起來,並傳遞至遠端的私用方法。
委派。
委派是 marshal-by-value 物件。委派內的物件可以是任意型別的可遠端處理物件:可序列化物件、MarshalByRefObject 物件或 ContextBoundObject 物件。唯一的例外是無法順利遠端處理介面方法的委派。委派會包裝介面方法的實作,這需要伺服器可取得用戶端的型別資訊。
覆寫物件上的方法。
基於效能原因,Object 方法上的虛擬方法一律會在呼叫它們的應用程式定義域中本機執行。已在遠端物件上覆寫下列任一方法時,則該方法的呼叫都只會前往遠端物件:
Equals
如果已覆寫,則會遠端執行這個虛擬方法。
GetHashCode
這個方法會在本機執行。
ToString
如果已覆寫,則會遠端執行這個虛擬方法。
Equals (靜態版本)
這個方法會在本機執行。
MemberwiseClone
這個方法會在本機執行。