2009-03-01 45 views
16

我想跨AppDomains使用一個對象。使用MarshalByRefObject的[Serializable]屬性或子類?

爲此,我可以使用[可序列化]屬性:

[Serializable] 
class MyClass 
{ 
    public string GetSomeString() { return "someString" } 
} 

或亞型的自MarshalByRefObject:

class MyClass: MarshalByRefObject 
{ 
    public string GetSomeString() { return "someString" } 
} 

在這兩種情況下,我可以使用類是這樣的:

AppDomain appDomain = AppDomain.CreateDomain("AppDomain"); 
MyClass myObject = (MyClass)appDomain.CreateInstanceAndUnwrap(
        typeof(MyClass).Assembly.FullName, 
        typeof(MyClass).FullName); 
Console.WriteLine(myObject.GetSomeString()); 

爲什麼這兩種方法似乎都有相同的效果?兩種方法有什麼不同?我應該在什麼時候採用這種方法呢?

編輯:在表面上我知道這兩種機制之間存在差異,但如果有人跳出布什並問我這個問題,我不能給他一個正確的答案。這些問題是相當開放的問題。我希望有人能比我更好地解釋它。

回答

20

使用MarshallByRef將在遠程AppDomain中執行您的方法。當您使用帶有Seri​​alizable對象的CreateInstanceAndUnwrap時,該對象的副本將發送到本地AppDomain,因此任何方法調用都將在本地AppDomain中執行。

如果你想要在AppDomain之間進行通信,請使用MarshallByRef方法。

一個例子:當你從MarshallByRef對象調用WhatIsMyAppDomain當您從Serializable對象調用

using System; 
using System.Reflection; 

[Serializable] 
public class SerializableClass 
{ 
    public string WhatIsMyAppDomain() 
    { 
     return AppDomain.CurrentDomain.FriendlyName; 
    } 
} 

public class MarshallByRefClass : MarshalByRefObject 
{ 
    public string WhatIsMyAppDomain() 
    { 
     return AppDomain.CurrentDomain.FriendlyName; 
    } 
}  

class Test 
{ 

    static void Main(string[] args) 
    { 
     AppDomain ad = AppDomain.CreateDomain("OtherAppDomain"); 

     MarshallByRefClass marshall = (MarshallByRefClass)ad.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "MarshallByRefClass"); 
     SerializableClass serializable = (SerializableClass)ad.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "SerializableClass"); 

     Console.WriteLine(marshall.WhatIsMyAppDomain()); 
     Console.WriteLine(serializable.WhatIsMyAppDomain()); 

    } 
} 

該代碼會顯示「OtherAppDomain」,和您的默認應用程序域的名稱。

5

爲什麼兩種方法都有相同的效果?

他們做不是有同樣的效果。

With MarshalByRefObject您正在跨AppDomain邊界引用一個對象。與[Serializable]對象的副本正在進行。如果對象的狀態在子域中被修改,然後再次檢查(或者在子AppDomain內部執行Console.WriteLine),將會顯示此信息。

+0

好的......改變了問題。它似乎*因爲兩種方法都具有相同的效果。 – 2009-03-01 12:25:58

2

MarshalByRefValueSerializable爲遠程處理/跨AppDomain通信實現了不同的語義。 MarshalByRefValue本質上通過代理對象爲您提供引用語義,而Serializable爲您提供了值語義(即複製對象的狀態)。

換句話說,MarshalByRefValue將允許您跨不同AppDomain修改實例,而Serializable不會。當你只需要從一個AppDomain獲取信息到另一個時,後者是很有用的,例如從一個AppDomain獲取異常的內容到另一個AppDomain。

+1

投票時請留言。謝謝。 – 2010-06-28 19:53:48

9

這些方法具有顯着不同的效果。

使用MarshalByRef版本,您正在創建對象的1個實例。它將生活在新創建的AppDomain中。對象的所有附件都通過TransparentProxy完成。

在Serializable版本中,您創建了2個對象實例。一個是在新創建的AppDomain中創建的。然後,CreateInstanceAndUnwrap調用將序列化此對象,並在原始應用程序域中反序列化它。這創建了與第一個完全獨立的對象的第二個版本。事實上,下一個GC幾乎可以肯定會消除原始對象,並且只剩下一個實例。

+0

+1鏈接到有關TransparentProxy的迷人博客條目。那篇文章真正爲我揭開了MarshalByRefObject(MBRO)的神祕面紗。現在我只是想知道是什麼一個Context和ContextBoundObject是:) – Qwertie 2012-01-02 00:08:00

相關問題