MarshalByRefObject特殊吗?

48

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

在远程处理中,有两种基本的传递对象的方法 - 要么将对象序列化(转换为一堆字节并在另一端重新构建),要么从MarshalByRefObject继承,这种情况下.NET会创建一些透明代理,并将所有方法调用转发回原始实例。

这很酷,就像魔法一样。但我不喜欢编程中的魔法。通过反射查看MarshalByRefObject,我没有看到任何使它与其他典型对象区别开来的地方。甚至没有奇怪的内部属性或任何其他标志。那么整个透明代理机制是如何组织的呢?我能否自己制作这样的机制?我能否创建一个替代品MyMarshalByRefObject,它不继承MarshalByRefObject但仍然具有相同的功能?还是说MarshalByRefObject在.NET引擎本身中受到了特殊处理,整个远程处理功能只能由非凡之人完成?


1
如果.NET Remoting以特殊方式处理所有继承自MarshalByRefObject的类,那么这是否可以称为“MarshalByRefObject很特别”?在.NET Remoting上使用反射器并找到魔法。顺便说一句,.NET Remoting已经过时,连同MarshalByRefObject一起。当然可以使用它,但WCF是当前主要的.NET“远程架构”。 - M.A. Hanin
1
WCF仍然支持MarshalByRefObject。 - Jack Ukleja
8
魔法在于抖动技术,它会特别处理MBRO类。它不再直接访问类中的字段,而是生成代码来使用CLR帮助方法。该方法知道对象是远程的,因此知道何时生成代理调用。 - Hans Passant
2个回答

20

关于RealProxy的文章有问题(或者至少是私有的 - Kirk Woll
1
谢谢提供信息,对我来说看起来也是如此 :-( 不幸的是,我在web.archive.org上也找不到它。也许尝试直接联系作者@thomas-danecker会有所帮助。 - akavel
1
只是为了明确,MarshalByRefObject和从它派生的类是特殊的,就像ValueTypes一样特殊:当处理MarshalByRefObject时,JIT会改变一些代码生成,并禁用某些优化。当您有一个引用任何派生自MarshalByRefObject的对象'x'时,JIT必须始终考虑x可能是远程对象的TransparentProxy。例如,内联可能被禁用,或者首先通过检查测试“x”是本地还是远程来进行保护。 - Qwertie
有趣的是,如果一个类X派生自MarhalByRefObject,你甚至可以创建“假”的X实例,其中根本不存在“真正”的X。这使得MarshalByRefObjects很像接口,因为可能(虽然不容易)用不是类型X但实现了X的“接口”的东西替换X对象。这篇关于该主题的文章非常酷:http://www.ikriv.com/en/prog/info/dotnet/RhinoMocks.html - Qwertie
该死的MarshalByRefObjects,因为错误处理问题。这个类已经过时了吗? - Johnny_D

4
我认为MarshalByRefObject并不是特别的。我相信它存在的全部原因在于其生命周期管理以及在服务器上如何进行垃圾回收。在LifetimeServices类文档中有一些关于这方面的好评论。
据我所知,远程调用的真正魔力是由远程调用基础设施自己完成的,当您设置主机时。MarshalByRefObject并没有执行跨应用程序域传输的真正工作。

1
在我的情况下,我只需要跨AppDomain边界进行通信(仅因为我需要卸载托管的.DLL)。这使得Remoting非常吸引人,因为它非常简单易用。 - Vilx-
好的,无论如何,如果MarshalByRefObject不是整个过程的关键,那么什么是关键呢?究竟是什么创建了神秘的代理等等? - Vilx-
看一下RemotingConfiguration.RegisterWellKnownServiceType()。我不得不查一下,因为我已经忘记了Remoting,因为我两年前转向了WCF。WCF可以做你想要的一切。你也会找到更多的资源。我感觉就像《小精灵》里那个老中国人警告孩子做出决定,但孩子还是喂了那个东西... - Dave Markle
如果我还没有用大量的代码编写,我会考虑使用它。但是,说实话,就我目前使用的情况来看,我无法想象有什么比它更简单和更容易编写的了。 - Vilx-
2
我不相信仅使用WCF就能控制第二个应用程序域中的代码。第一步是在第二个域中创建一个类型的实例并在当前域中取消其代理。从那时起,您就有了一个桥梁,可以通过它向第二个域发送命令。如何仅使用WCF构建该桥梁?如何创建服务端点?我从未见过如何做到这一点的示例... - user1228
1
此外,点个赞。使用代理时,生命周期管理非常重要(任何曾经在代理下面收集对象的人都知道这一点)。MBRO 包含与此相关的代码。 - user1228

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接