可远程处理的和不可远程处理的对象

请一定记住,在某个应用程序域中创建并因此特定于它的对象可以在此域中直接调用,但此对象必须经过一些特殊处理后才可以在它的域以外使用。并非每种类型的对象都可以跨越域边界高效地发布或使用;因此,必须根据应用程序的需要决定要发布哪种类型的对象。对于分布式应用程序,对象分为两种简单的类别:不可远程处理的和可远程处理的对象。

不可远程处理的对象

某些对象不能离开它们的应用程序域;它们永远不会被封送处理,原因是它们不声明序列化方法。这些不可远程处理的对象主要是在创建它们的同一应用程序域内使用,并且始终从该应用程序域中直接访问。.NET Framework 类库中的大多数基类是不可远程处理的对象。不可远程处理的对象无法在其他应用程序域中复制或表示。这些对象只能从它们的初始应用程序域中进行访问。

可远程处理的对象

可远程处理的对象可以使用代理在其应用程序域或上下文之外进行访问,也可以复制它们并且可以将这些副本传递到它们的应用程序域或上下文外;也就是说,某些可远程处理的对象通过引用传递,而另一些通过值传递。

可远程处理的对象是能在大范围的分布式环境中正常运行的对象。有两种主要的可远程处理的对象:

  • 值封送对象,它们被复制并从应用程序域传递。

  • 引用封送对象,将为其创建代理,而该代理由客户端用于远程访问对象。

值封送对象

值封送 (MBV) 对象声明它们的序列化规则(通过实现 ISerializable 来实现其自身的序列化,或者通过用 SerializableAttribute 修饰,该属性通知系统自动序列化该对象),但是不扩展 MarshalByRefObject。远程处理系统创建这些对象的完整副本并将副本传递到进行调用的应用程序域。一旦副本到达调用方的应用程序域内,对该副本的调用就是对该副本的直接调用。此外,作为参数传递的 MBV 对象也会通过值传递。除了声明 SerializableAttribute 属性或实现 ISerializable 之外,您不需要执行其他任何操作即可将类的实例跨越应用程序或上下文边界通过值进行传递。

备注

从 .NET Framework 1.1 版开始,远程处理基础结构不会自动对服务器上的某些类型进行反序列化。如果您的方案存在这种情况,则必须先将服务器的反序列化级别设置为 Full,然后服务器才能反序列化并使用您的 MBV 对象。有关更多信息,请参见 .NET 远程处理中的自动反序列化

如果就性能或处理方面的原因而言,将对象的完整状态和任何可执行功能移动到目标应用程序域具有一定的意义,则应使用 MBV 对象。在许多方案中,这减少了跨网络、进程和应用程序域边界的冗长而耗费资源的往返过程。MBV 对象还可以从对象的原始应用程序域内直接使用。在这种情况下,由于不进行任何封送处理,因此不创建任何副本而且访问非常高效。

另一方面,如果发布的对象非常大,那么在繁忙的网络上传递整个副本对于应用程序来说可能不是最佳的选择。此外,永远不会将对复制对象的状态所做的更改传回到起始应用程序域中的原始对象。在抽象级别上,这种方案类似于客户端浏览器所请求的静态 HTML 页的方案。服务器复制文件,将其写入到流中,发送出去,然后忘掉它。所有后续的请求都只是对其他副本的其他请求。

如果您未扩展已实现 ISerializable 的类,则通过使用 SerializableAttribute 创建值封送类型。在此情况下,必须为您的类型实现 ISerializable。

远程处理系统广泛使用可序列化的对象。对其他应用程序域中的对象的引用(由 ObjRef 类在远程处理系统中表示)本身是可序列化的;必须能够将它精确地复制并将副本发送给请求。实现 IMessage 的消息对象也是如此,这是因为它们是调用数据和所有其他必需的对象引用的一般容器。另外,仅传输数据的对象通常是可序列化的对象。例如,DataSet 扩展实现 ISerializable 的 MarshalByValueComponent

远程处理用户定义的异常

系统定义的异常都是值封送类型(它们实现 ISerializable 接口),当被远程对象引发时,它们将自动复制到调用方(如果远程处理配置允许)。(从 .NET Framework 1.1 版开始,<customErrors> 元素必须设置为 off 才能使异常流向调用方。)

有关如何创建可由远程对象引发并由远程调用方捕获的异常类型的更多信息,请参见如何:创建可由远程对象引发的异常类型

引用封送对象

引用封送 (MBR) 对象是至少扩展 System.MarshalByRefObject 的可远程处理的对象。根据已声明的激活类型,当客户端在它自己的应用程序域中创建 MBR 对象的实例时,.NET 远程处理基础结构在调用方的应用程序域中创建表示该 MBR 对象的代理对象,并向调用方返回对此代理的引用。然后,客户端将在此代理上进行调用。远程处理将封送这些调用,将其发送回起始应用程序域,并引发对实际对象的调用。

备注

如果客户端与 MBR 对象位于同一个应用程序域中,基础结构将向客户端返回对该 MBR 对象的直接引用,从而避免封送处理的系统开销。

如果 MarshalByRefObject 作为参数传递,当调用到达时,它将变成另一个应用程序域中的代理。MBR 返回值,而 out 参数以相同的方式工作。

备注

从 .NET Framework 1.1 版开始,远程处理基础结构不会自动对服务器上的某些类型进行反序列化。例如,要获取对作为参数传递的 MBR 对象的支持,必须将服务器的反序列化级别设置为 Full,然后服务器才能反序列化并使用 MBR 参数。有关更多信息,请参见 .NET 远程处理中的自动反序列化

当对象的状态和任何可执行的功能应处在创建它的应用程序域中时,应当使用 MBR 对象。例如,由于操作系统句柄在其他应用程序域中、其他进程中或其他计算机上将是无意义的,因此具有内部字段且该内部字段是操作系统句柄的对象应扩展 MarshalByRefObject。有时对象可能大得难以想像;对于功能强大的服务器还行,但在通过网络发送到 33.6 KBps 的调制解调器时就不行了。

上下文绑定对象

上下文绑定对象是从 System.ContextBoundObject(它自身从 System.MarshalByRefObject 继承)继承的 MBR 对象。您可以将上下文当作应用程序域的一部分,它在执行期间为其中的对象提供丰富的环境。例如,上下文可以确保对象不会同时被多个线程访问。每个应用程序域都有一个默认的上下文。大多数托管代码都使用该域的默认上下文直接从同一个应用程序域中创建对象并调用成员,而不存在与上下文相关的问题。所有从 ContextBoundObject 继承的类型都作为代理向其他上下文(同一个域中或其他域中)公开。

例如,假定有一个某类型上的方法,该类型是事务的一部分,因而受到特定于在其中创建它的上下文的规则的约束。该类型应该从 ContextBoundObject 继承,这样就可以从对象本身的上下文访问该对象,而且系统可以强制实施有关与该对象及其方法关联的事务的规则。如果从同一应用程序域中的其他上下文调用 ContextBoundObject,则将为调用方创建代理,但是上下文间的通信不通过信道系统,在此情况下这将提高调用效率。

由于跨越每个边界会占用处理时间,因此在确定服务器应该是哪种类型的可远程处理对象之前,应该确定对象必须跨越哪些边界。特定于某个特定上下文的对象只能从该上下文中直接访问。对于特定于某个特定应用程序域的对象也是如此。要远程处理这两者中的任一种对象,在从服务器对象所特定于的边界内调用该服务器对象之前,远程处理系统必须成功通过上下文边界、应用程序边界或是成功通过这两种边界。如果调用对象不需要上下文检查,则不应让远程类型扩展 ContextBoundObject;MarshalByRefObject 将执行得更好。如果确实需要上下文检查,则应当扩展 ContextBoundObject,但须知道,在实际调用对象前,必须跨越附加的边界。

发布范围

不同的远程处理系统以不同的方式决定可以远程使用哪些成员以及哪些类型的成员。.NET 远程处理向其他应用程序域公开对象,就像这些对象是本地对象一样,但如下对象例外:

  • 静态成员。

    静态字段和方法永远不会进行远程处理,而且字段访问是通过直接内存进行的。也就是说,.NET 远程处理总是处理某种形式的实例成员。

  • 实例字段和访问器。

    对于实例字段和访问器方法,系统在运行时插入检查以确定对象是否是代理。如果不是代理,字段访问就是直接的。否则,代理会向调用方提供访问器。

  • 私有方法。

    不能远程处理私有方法。不能在远程包装委托并将其传递给私有方法。

  • 委托。

    委托是值封送对象。委托内的对象可以是任意类型的可远程处理的对象:可序列化的对象、MarshalByRefObject 对象或 ContextBoundObject 对象。唯一的例外是接口方法的委托不能成功地进行远程处理。该委托将包装接口方法的实现,从而要求向服务器提供客户端的类型信息。

  • 在对象上重写方法。

    由于性能的原因,Object 方法上的虚拟方法总是在调用它们的应用程序域中本地执行。当下列方法已经在远程对象上重写时,对它们的调用只会转向远程对象。

    • Equals 

      此虚拟方法在重写时远程执行。

    • GetHashCode 

      该方法在本地执行。

    • ToString 

      此虚拟方法在重写时远程执行。

    • Equals(静态版本)

      该方法在本地执行。

    • MemberwiseClone 

      该方法在本地执行。

请参见

任务

如何:创建可由远程对象引发的异常类型

其他资源

.NET Framework 远程处理概述
使对象可远程处理