欢迎来到.net学习网

欢迎联系站长一起更新本网站!QQ:879621940

您当前所在位置:首页 »  .NET本质论第一卷:公共语言运行库教程 » 正文

本教程章节列表

AppDomain和对象(回顾)

创建时间:2013年04月03日 15:27  阅读次数:(3930)
分享到:
本章开始就将AppDomain作为执行范围。其中,大部分讨论都是将AppDomain描绘成对象和类型的“家”。尤其是,对象的作用域就是特定的AppDomain,并且,对象引用只是引用同一个AppDomain中的对象。然而,在已经谈到的AppDomain接口方面还有一点不一致性。所谓的不致性就是SetData和GetData机制。

示例8.3将代码插入到外部AppDomain中。在那个例子中,程序使用SetData和GetData机制,从一个AppDomain到另一个AppDomain传递被加载的程序集的数量。然而,通过考察下面两个方法的签名,你可以将对象引用保存在某个AppDomain的公共属性中,并由另一个AppDomain提取(并且使用!)它:
static public void SetData(String name,object value);
static public object GetData(string name);

事实上,这正是示例8.3代码所做的工作。你可能还想将某个AppDomain的对象引用迁移到另一个域中,而这个对象引用又是AppDomain相关的。答案就是封送(marshaling)。

CLR将所有对象、值和对象引用的作用域定为特定的AppDomain。当需要将引用或者值传给另一个AppDomain时,必须首先封送它。CLR封送的基础架构大部分是在System.Runtime.Remoting命名空间下。特别是,System.Runtime.Remoting.RemotingServices有两个静态方法Mashal和Unmashal,它们是封送的基础。

RemotingServices.Mashal方法接收类型System.Object的对象引用,并且返回一个可序列化的System.Runtime.Remoting.Remoting Services.objRef对象,它能够以序列化格式传给其他AppDomain。在接受序列化的ObjRef的基础上,通过使用RemotingServices.Unmashal方法可以获得合法的对象引用。当在外部AppDomain中调用AppDomain.SetDaLa时,CLR调用RemotingServices.Mashal方法。类似地,在外部AppDomain中调用AppDomain.GetData时,将返回一个封送的引用。它在方法完成之前,通过RemotingServices.Unmashal方法进行转换。

当你封送一个对象引用时,该对象的具体类型确定封送将如何实际工作。如表8.4所示,共有三种场景。
灵活性(aglity)与对象

默认情形下,类型是远程未知的(remote-unaware),并且不支持跨AppDomain的封送。对远程未知类型的实例进行封送将导致失败。

如果类型直接或者间接派生于System.MarshalByRefObject,那么,这个类型就是AppDornain绑定的(AppDomain-bound)。AppDomain绑定的类型的实例将按引用封送。这意味着CLR将给被封进对象(引用)的接收者一个代理,它将所有成员的访问路由(转发)到该对象所属的AppDomain(home AppDomain)中。从技术上讲,代理只是将实例成员的访问转发到对象所属的AppDomain.从不转发静态方法。

那些没有派生于MarshalByRefObject但却能够支持对象序列化(通过[System.Serializable]伪定制特性)的类型被认为与任何AppDomain都是非绑定的(unbound)。非绑定类型的实例是按值封送的。这意味着CLR将给被封送对象(引用)的接收者提供一个原始对象的非连接的克隆,图8.10展示了这三种行为。
跨AppDomin封送对象

当对一个跨AppDomain的代理进行调用时,封送就会隐式地发生。CLR将方法调用的输入参数封送到序列化的请求消息中,由CLR发送到目标AppDomain。当目标AppDomain接收到序列化的请求后,它首先对这个消息进行反序列化,并将参数压入到新的堆栈帧中,在CLR将这个方法分发到目标对象之后,CLR将输出参数和返回值封送到序列化的响应消息中.由CLR送回调用方的AppDomain.然后,CLR取消它们的封送(unmarshal),同时将它们放回调用方的堆栈上。

图8.11展示了跨AppDomain的远程处理架构。CrossAppDomainChannel的工作就是获取位块传输(BLT)的堆栈帧,并将它序列化到缓冲区中,用于通过信道发送到目标AppDomain。目标AppDomain的信道基础结构对消息进行反序列化,并将其传递到适合的消息接收器上,最终形成堆栈帧,并且在目标对象上调用方法。每个AppDomain维护—个身份表(identity table),它在被封送对象的相应消息接收器上映射一个唯一的识别符(名为URI)。该URI在被封送的对象引用中出现,并且代理会在每一个向外的请求消息中设置它。
跨域的方法调用

当使用跨AppDomain的代理时,需要特别强调的是:CLR必须将这两个AppDomain中的元数据都加载进来,用于代理用到的所有类型。即,这两个AppDomain必须访问同样的程序集。并且,当这两个AppDomain驻留在不同的机器上时,这两台机器必须访问共享类型的元数据。

例如,考虑下面的程序,它将在一个子AppDomain中创建一个对象:
using System;
class App{
static void Main(){
//创建域
AppDomain child=AppDomain.CreateDomain(“c”,null);
//在新的域中创建对象
Object proxy=child.CreateInstance(“someassm”,”Bob”).Unwrap();

//向下类型转换,并且调用
Bob b=(Bobproxy;
b.f();
}
}

由于代理需要Bob的元数据,因此,子域和父域都需要访问包含Bob元数据的someassm程序集。

细心的读者可能注意到上面示例中的Unwrap调用.AppDomain.CreateInstance方法并不返回正常的对象引用。更进一步说,它返回一个象句柄(object handle)。对象句柄类似于被封送的对象引用。AppDomain.Createlnstance返回一个对象句柄,而不是真实的对象引用,这样便避免请求调用方AppDomain中的元数据。例如,考虑前面程序的变体:
using System;
class App{
static void Main()
{
//创建两个域
AppDomain c1=AppDomain.CreateDoamin(“c1”,null);
AppDomain c2=AppDomain.CreateDoamin(“c2”,null);
//在第一个域中创建对象
Object handle=c1.CreateInstance(“someassm”,”Bob”);
//在c2的属性中保存对象的句柄
c2.SetData(“HeresYourHandle”,handle);
//运行某个程序
c2.ExecuteAssembly{“foo.exe”,null,null};
}
}

在这个程序中,由于AppDomain.CreateInstance的结果没有在父域中解除封装(unwrapped),因而,CLR不需要在父域中加载“someassm”程序集。那是因为直到调用Unwrap时,CLR才需要元数据,而在这里CLR将只在第二个子域中执行)。

我们走到哪儿了
AppDomain确定了类型和对象运行时的作用域。AppDomain是被用作独立于应用程序的模型,它们可能(或者不可能)共享os进程。AppDomain通过程序集解析器和加载器,可以广泛地变互并且,支持更为丰富的封送层,从而支持应用程序之间的通信。`€{US0WcTW
来源:.net学习网
说明:所有来源为 .net学习网的文章均为原创,如有转载,请在转载处标注本页地址,谢谢!
【编辑:Wyf】

打赏

取消

感谢您的支持,我会做的更好!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

最新评论

共有评论0条
  • 暂无任何评论,请留下您对本文章的看法,共同参入讨论!
发表评论:
留言人:
内  容:
请输入问题 96+56=? 的结果(结果是:152)
结  果: