欢迎来到.net学习网

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

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

本教程章节列表
最新评论

版本化的问题

创建时间:2012年08月24日 14:33  阅读次数:(5929)
分享到:

前面有关程序集解析器如何确定加载程序集版本的讨论,主要集中在CLR用到的机制。至于开发人员应该使用什么策略,确定何时、如何以及为什么版本化(version)程序集,目前都还没有讨论。由于前面所描述的平台截止到本书写作时,还没有实际发布,因此,如果要列出经过宝贵经验证明行之有效的“最佳实践”,还存在着某种困难。不过,着眼于CLR的已知状态,

图2.15:文化相关的探测

并由此推断出一些指导方针,也还是很有参考价值的。
值得特别注意的是,程序集被版本化为一个单元。如果替换程序集中文件的一个子集,而不更新版本号,这将导致不可预测的结果。为此,本节的剩余部分将程序集的版本化看作一个整体,而不是在程序集中版本化个别文件。
何时更新版本号是一个有趣的问题。显而易见,如果类型的公共约定改变了,类型的程序集必须被赋予一个新的版本号。否则,对于依赖于类型签名的某个版本的程序,当一个不同签名的类型被加载时,就会出现运行时间错误。

这意味着假如你增加或删除公共类型的public或者protected成员,你就必须更新类型程序集的版本号;如果你修改公共类型的public或者protected成员的签名(例如,增加一个方法参数,或者改变一个字段的类型),那么,你也需要新的程序集版本号。这些都是必须遵守的规则,违背它将会导致不可预测的结果。

更难回答的问题是:修改程序集而不影响程序集类型的公共签名。例如,修改标记为private或internal的成员,就被认为是非破坏(non-breaking)修改;至少就签名匹配而言是这样的。因为程序集以外的代码不会依赖private或internal成员,所以,在运行时不会出现签名不匹配的情况。遗憾的是,签名不匹配只是一小部分而已。
即使没有可见的签名被公开修改,程序集的每次构建都要产生新版本,有关它的争论是情理之中的。事实上,即使是对单个方法体看似简单的修改,却能影响使用程序集的程序的行为,这种影响是微妙的却是实实在在的。如果开发人员为程序集的每次构建提供了唯一的版本号,那么在部署时,代码将被检测到特定的构建版本。

反对为程序集的每次构建提供唯一版本号的理由是:固定到代码的“安全”将不会被重新构建的新版程序所沿用。然而,在面对发行者策略文件时,这个理由就经不起考验了。对于使用每次构建使用新版本号的开发人员,他们期望提供发行者策略文件,说明程序集的哪些版本是向后兼容的。默认情况下,它能够实现低版本程序集到新版本的(并且是更快的或者更少bug的)自动升级。当程序集开发人员假设错误后,每个应用程序都能使用其配置文件中的publisherPolicy元素,停止自动升级。本质上说,是在“安全模式”下运行应用程序。
前面已经讨论过,CLR程序集解析器能够通过CODEBASE提示、私有查找路径以及GAC,支持多版本程序集的并行安装(side-by-side installation)。这允许给定程序集的多个版本在文件系统中和平共处。然而,如果有多于一个这样的程序集被独立程序或单个程序实际加载到内存中,那么,事情在某种程度上是不可预测的。并行执行比并行安装要难处理得多。

同时在内存中支持多版本的主要问题是:对于运行时,那些程序集所含有的类型是不同的。也就是说,如果某个程序集含有被称为Customer的类型,那么,当程序集的两个不同版本被加载时,内存里就有了两个不同的类型,每个类型都有它自己的唯一标识。这就产生一些很大的缺陷。其中一个就是每个类型都有它自己的静态字段拷贝。如果类型需要某个共享状态,并期望它独立于已被加载的版本,那么,就无法套用静态字段的解决方式。准确地说,开发人员需要考虑到版本化的影响,重新编写代码,并将共享状态存储在非版本敏感(not version-sensitive)的位置。一种方式就是将共享状态存储在某个运行时提供(runtime-privided)的地方,例如,ASP.NET应用程序对象。另一种方式是定义一个只包含共享状态的单独类型,并作为静态字段。开发人员在一个单独的程序集中部署这个类型,并且,使该程序集不被版本化,这样,就确保对于给定的应用程序,静态字段在内存中只有一个拷贝。
当版本化的类型作为方法参数被传递时,就产生了与并行执行相关的另一个问题。如果某个方法的调用方和被调用方对加载程序集的版本持不同意见,那么,调用方将可能传递被调用方不知道的参数。为了避免这个问题,开发人员对于所有公共(交叉程序集)方法,总是使用版本恒定(version-invariant)类型定义参数。更重要的是,这些共享类型需要被部署到单独的程序集中,它本身不会被版本化。

用于程序集的元数据具有三个特别的特性,它们允许开发人员能够指定程序集的版本是否同时被加载。如果没有这样的特性出现,那么,在所有的场景中,假定程序集的并行执行是安全的。nonsidebysideappdomain特性标明只有一个程序集版本能按每个AppDomain被加载;nonsidebysideprocess特性标明只有一个程序集版本能按每个进程被加载;最后,nonsidebysidemachine特性标明对于整个计算机只有一个程序集版本能被一次性加载。截止到本书写作时,这些元数据的位被现行的程序集解析器和加载器忽略。然而,它们确实能够取到提示作用,这个提示有望在CLR的未来版本中实施。

我们走到哪儿了

模块和程序集是生成CLR程序块的组件。每个CLR类型驻留在一个明确的物理文件中(称为模块),它包含了代码和元数据。为了便于部署,模块必须与一个逻辑的程序集关联,它赋给模块的类型一个完全限定的名字。CLR加载器主要针对程序集工作,模块(与类型)只在它们被需要时才被加载。程序集的名字是独立于位置的,因而,程序集加载器在加载程序集之前,需要将名字解析为物理的文件路径或URL。这样,不仅部署和版本化更为灵活,而且通过公钥和数字签名,确保原创组件不被随意修改。

来源:.net学习网
说明:所有来源为 .net学习网的文章均为原创,如有转载,请在转载处标注本页地址,谢谢!
【编辑:Wyf】

打赏

取消

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

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

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

最新评论

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