MarshalByRefObject 是特殊的吗?

Posted

技术标签:

【中文标题】MarshalByRefObject 是特殊的吗?【英文标题】:Is MarshalByRefObject special? 【发布时间】:2011-02-12 19:46:33 【问题描述】:

.NET 有一个叫做远程处理的东西,你可以在不同的应用程序域甚至物理机器之间传递对象。我不完全理解魔法是如何完成的,因此提出了这个问题。

在远程处理中,有两种传递对象的基本方式——它们可以被序列化(转换为一堆字节并在另一端重建)或者它们可以从MarshalByRefObject 继承,在这种情况下 .NET 使一些透明代理和所有方法调用都转发回原始实例。

这很酷,就像魔术一样。而且我不喜欢编程中的魔法。用反射器查看MarshalByRefObject,我看不到任何可以将其与任何其他典型对象区分开来的东西。甚至没有奇怪的内部属性或任何东西。那么整个透明代理是如何组织的呢?我可以自己做这样的机制吗?我可以创建一个不会从MarshalByRefObject 继承但仍会保持相同行为的备用MyMarshalByRefObject 吗?还是MarshalByRefObject 受到 .NET 引擎本身的特殊处理,而整个远程处理壮举是凡人无法复制的?

【问题讨论】:

如果 .NET Remoting 以特殊方式处理从 MarshalByRefObject 继承的所有类,这是否符合“MarshalByRefObject 是特殊的”的条件?在 .NET Remoting 上使用 Reflector 并找到魔力。顺便说一句,.NET Remoting 以及 MarshalByRefObject 都已过时。当然可以使用它,但 WCF 是 .NET 中当前占主导地位的“远程处理架构”。 WCF 仍然支持 MarshalByRefObject 神奇之处在于抖动,它对 MBRO 类进行了特殊处理。它不再直接访问类中的字段,而是生成代码以使用 CLR 帮助器方法。它知道对象是远程的,因此知道何时生成代理调用。 【参考方案1】:

神奇之处似乎在于一个特殊的 TransparentProxy 类 - .NET 运行时以一种特殊的方式处理它。

如果您想使用它,请参阅an article about RealProxy 如果您想了解更多关于“魔法”的信息,请参阅an article on TransparentProxy implementation。 有关基本概述,请尝试the MSDN article "Remoting: A Technical Overview"。

我认为MarshalByRefObject 可能包含一些额外的内部信息,这些信息可能对这种机制有所帮助,但我没有对此进行过多研究。

【讨论】:

关于 RealProxy 的文章被破坏(或至少 private 感谢您的信息,对我来说也是如此 :-( 不幸的是,我也无法在 web.archive.org 上找到它。也许尝试亲自联系作者 @thomas-danecker 可能会有所帮助 要清楚一点,MarshalByRefObject 和派生自的类是特殊的,与 ValueTypes 的特殊方式非常相似:JIT 在处理 MarshalByRefObject 时会更改其某些代码生成,并禁用某些优化.当您引用派生自 MarshalByRefObject 的任何对象“x”时,JIT 必须始终考虑 x 是远程对象的透明代理的可能性。例如,内联可能被禁用,或者通过检查来保护“x”首先是本地还是远程。 有趣的是,如果类 X 派生自 MarhalByRefObject,您甚至可以创建 X 的“假”实例,其中根本不存在“真实”X。这使得 MarshalByRefObjects 很像接口,因为可以(虽然不容易)用不是 X 类型但实现 X 的“接口”的东西替换 X 对象。这篇关于这个主题的文章很酷:ikriv.com/en/prog/info/dotnet/RhinoMocks.html 该死的 MarshalByRefObjects,因为错误处理问题。这个类过时了吗?【参考方案2】:

我相信 MarshalByRefObject 并不是那么特别。我相信它存在的全部原因在于它的生命周期管理以及它是如何在服务器上进行垃圾收集的。在LifetimeServices 类文档中有一些关于这方面内容的好方法。

AFAIK,远程处理的真正魔力是在您设置主机时由远程处理基础设施自己完成的。 MarshalByRefObject 没有做任何跨 AppDomain 编组的实际工作。

【讨论】:

在我的情况下,我只需要跨 AppDomain 边界进行通信(这只是因为我需要卸载托管的 .DLL)。这使得 Remoting 很有吸引力,因为它使用起来非常简单。 好吧,无论如何,如果 MarshalByRefObject 不是整个过程的关键,那是什么?究竟是什么创造了神秘的代理等? 看看 RemotingConfiguration.RegisterWellKnownServiceType()。我不得不查找它,因为我忘记了 Remoting,因为我在 2 年前切换到 WCF。 WCF 可以做你想做的一切。你也会找到更多的资源。我感觉就像《小精灵》中的那个中国老人警告孩子他的决定,但孩子还是继续喂东西…… 我不相信单独使用 WCF 来控制第二个 appdomain 中的代码。第一步是在第二个域中创建一个类型的实例,并在当前域中解开它的代理。从那时起,您就有了一座桥,您可以通过该桥将命令发送到第二个域。您将如何仅使用 WCF 构建这座桥?您如何创建服务端点?从来没有见过如何做到这一点的例子...... 另外,+1 这个。生命周期管理对于代理来说非常重要(任何从代理下收集过对象的人都知道)。 MBRO 包含与此相关的代码。

以上是关于MarshalByRefObject 是特殊的吗?的主要内容,如果未能解决你的问题,请参考以下文章

MarshalByRefObject 生命周期

混合 MarshalByRefObject 和 Serializable

关于MarshalByRefObject的解释

FreeRTOS 优先级 1 是特殊的吗?

使用 MarshalByRefObject 的 [Serializable] 属性或子类?

AppDomain 和 MarshalByRefObject 生命周期:如何避免 RemotingException?