使用 MarshalByRefObject 的 [Serializable] 属性或子类?
Posted
技术标签:
【中文标题】使用 MarshalByRefObject 的 [Serializable] 属性或子类?【英文标题】:Use the [Serializable] attribute or subclassing from MarshalByRefObject? 【发布时间】:2010-10-10 15:03:56 【问题描述】:我想跨 AppDomain 使用一个对象。
为此,我可以使用 [Serializeable] 属性:
[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());
为什么这两种方法似乎具有相同的效果?两种方法有什么区别?我什么时候应该优先选择一种方法而不是另一种方法?
编辑:表面上我知道这两种机制之间存在差异,但如果有人从灌木丛中跳出来问我这个问题,我无法给他正确的答案。这些问题是相当开放的问题。我希望有人能比我做得更好。
【问题讨论】:
【参考方案1】:使用 MarshallByRef 将在远程 AppDomain 中执行您的方法。当您将 CreateInstanceAndUnwrap 与 Serializable 对象一起使用时,会将该对象的副本复制到本地 AppDomain,因此任何方法调用都将在本地 AppDomain 中执行。
如果您想要在 AppDomain 之间进行通信,请使用 MarshallByRef 方法。
一个例子:
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());
当您从 MarshallByRef 对象调用 WhatIsMyAppDomain 时,此代码将显示“OtherAppDomain”,当您从 Serializable 对象调用时,将显示您的默认 AppDomain 名称。
【讨论】:
【参考方案2】:这些方法具有截然不同的效果。
使用 MarshalByRef 版本,您正在创建对象的 1 个实例。它将位于新创建的 AppDomain 中。对对象的所有访问都是通过TransparentProxy 完成的。
使用 Serializable 版本,您将创建对象的 2 个实例。一个是在新创建的 AppDomain 中创建的。 CreateInstanceAndUnwrap 调用将序列化这个对象并在原始应用程序域中反序列化它。这将创建完全独立于第一个版本的对象的第二个版本。事实上,下一次 GC 几乎肯定会消除原始对象,而您将只剩下一个实例。
【讨论】:
+1 链接到关于透明代理的迷人博客条目。那篇文章真的为我揭开了 MarshalByRefObject (MBRO) 的神秘面纱。现在我只是想知道 Context 和 ContextBoundObject 到底是什么:)【参考方案3】:为什么这两种方法有相同的效果?
它们确实不具有相同的效果。
使用MarshalByRefObject
,您正在跨 AppDomain 边界引用一个对象。使用[Serializable]
正在制作对象的副本。如果在子域中修改了对象的状态然后再次检查(或在子 AppDomain 中执行 Console.WriteLine
),则会显示此信息。
【讨论】:
好的...已经改变了问题。 似乎因为这两种方法具有相同的效果。【参考方案4】:MarshalByRefValue
和 Serializable
为远程处理/跨 AppDomain 通信实现不同的语义。 MarshalByRefValue
本质上是通过代理对象为您提供引用语义,而Serializable
为您提供值语义(即复制对象的状态)。
换句话说,MarshalByRefValue
将允许您跨不同的 AppDomain 修改实例,而 Serializable
不会。当您只需要从一个 AppDomain 获取信息到另一个 AppDomain 时,后者很有用,例如从一个 AppDomain 到另一个 AppDomain 获取异常的内容。
【讨论】:
请在投反对票时发表评论。谢谢。以上是关于使用 MarshalByRefObject 的 [Serializable] 属性或子类?的主要内容,如果未能解决你的问题,请参考以下文章
混合 MarshalByRefObject 和 Serializable