框架升级后某个类型所在程序集发生转移,应用还能正常运行吗?

简介:

所谓类型转移(Type Forwarding)就是将定义在某个程序集中的类型转移到另一个程序集中。我们先通过一个简单的实例让读者朋友们对类型转移有一个感官上的认识。我们利用Visual Studio创建一个针对.NET Framework 3.5的控制台应用,并编写如下一端简单的程序输出两个常用的类型(Function<T>和TimeZoneInfo)所在程序集的名称。现在我们直接运行这个程序,会在控制台上得到如下所示的输出结果,可以看出.NET Framework 3.5(CLR 2.0)环境下的这两个类型定义在程序集System.Core.dll中。

   1: public class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         Console.WriteLine(typeof(Func<>).Assembly.FullName);
   6:         Console.WriteLine(typeof(TimeZoneInfo).Assembly.FullName);
   7:     }
   8: }

输出结果:

image

现在我们对该程序的配置文件(App.config)作如下的修改,其目的在于采用CLR 4.0来运行该程序。再次运行该程序集之后,我们会在控制台上得到不一样的输出结果。通过如下所示的输出结果我们可以看出当.NET Framework从3.5升级到4.0的时候,将原本定义在程序集System.Core.dll中的部分类型转移到了程序集mscorelib.dll之中。

   1: <configuration>
   2:   <startup>
   3:     <supportedRuntime version="v4.0"/>
   4:   </startup>
   5: </configuration>

输出结果:

image

跨程序集之间的类型转移帮助框架或者类库的提供者解决这样的难题:某个类型在框架1.0版本的时候定义在程序集A中,当升级到2.0的时候被转移到了程序集B中,使用旧版本的应用可以在不做任何修改的情况下直接对使用的升级后的框架程序集。类型转移需要使用到一个特殊的特性TypeForwardedToAttribute,我们现在通过一个简单的实例来演示如何利用这个特性来解决框架或者类库升级过程在类型跨程序集转移的问题。

这个演示的场景如上图所示:代表应用的App.exe在编译的时候引用了代表框架的程序集Lib.dll,具体使用的是定义其中的类型Foobar,框架进行升级之后新增了一个程序集Lib2.dll,原来定义在Lib.dll中的类型Foobar被转移到了Lib2.dll中。充分利用CLR针对类型转移的支持,我们只需要直接部署新版本的Lib.dll(不包含类型Foobar)和Lib2.dll,现有的程序能够照常运行。

我们利用Visual Studio创建了如上图所示的解决方案。类库项目Lib1代表版本1.0的框架,我们将编译生成的程序集名称设置成Lib,并在其中定义了一个类型Foobar。控制台应用直接应用Lib1,并与其中编写了如下一段简单的程序,其目的在于确认类型Foobar所在的程序集。

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         Console.WriteLine(typeof(Foobar).AssemblyQualifiedName);
   6:         Console.Read();
   7:     }
   8: }
类库项目Lib2和Lib3编译生成代表框架升级之后的两个程序集,我们通过修改项目属性将目标程序集名称设置成Lib和Lib2,Lib2具有针对Lib3的项目引用。我们在Lib3中重新定义了代表被转移的类型Foobar,而Lib2实际上是一个空的项目。要体现类型Foobar从Lib.dll转移到Lib2.dll,我们需要在Lib2项目上应用如下所示的一个 TypeForwardedToAttribute特性(定义在AssemblyInfo.cs中)。
   1: [assembly:TypeForwardedTo(typeof(Foobar))] 

现在我们对整个解决方案进行编译,然后定位到控制台App项目编译后的输出目录(app\bin\debug),并将项目Lib1编译生成的程序集Lib.dll删除,而将Lib2和Lib3编译生成的程序集Lib.dll和Lib2.dll拷贝到该目录下。现在我们直接运行App.exe,我们会在控制台上得到如下所示的输出结果。

image

如果某个项目应用了TypeForwardedToAttribute特性指向定义在另一个程序集中的被转出类型,类型转移相关的信息会体现在编译生成的元数据中。就我们的实例而言,项目Lib2编译的生成的程序集通过如下的元数据来指向被转移出去的类型所在的目标程序集。

   1: .class extern forwarder Lib.Foobar
   2: {
   3:   .assembly extern Lib2
   4: }

当App.exe被执行的时候,由于元数据体现的依然是针对程序集Lib.dll的引用,所以CLR依然会试图从该程序集中加载类型Foobar。但是通过分析程序集Lib.dll的元数据,CLR知道Foobar已经被转移到程序集Lib2.dll中,所以定义在其中的同名类型Foobar最终会被加载。


作者:蒋金楠
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
7月前
自动检查以确保依赖项始终与使用的electron版本相匹配的小技巧
自动检查以确保依赖项始终与使用的electron版本相匹配的小技巧
111 0
|
1月前
|
存储 网络协议 搜索推荐
宏函数的代码替换机制会对程序的可移植性产生什么影响
宏函数的代码替换机制可能导致程序可移植性降低,因为它在预处理阶段直接替换文本,可能引发类型不匹配、副作用等问题,不同编译器和平台表现不一。
|
4月前
|
存储 Kubernetes 监控
软件环境管理问题之不可变环境的定义如何解决
软件环境管理问题之不可变环境的定义如何解决
|
4月前
|
存储 Kubernetes 中间件
软件环境管理问题之保证环境的一致性如何解决
软件环境管理问题之保证环境的一致性如何解决
|
6月前
|
存储 Swift
Swift开发——属性检查器
Swift中的属性检查器(willSet, didSet)允许在设置存储属性值前后执行代码。在类`Circle`中,属性`radius`使用属性观察器:willSet在赋值前检查值,若值为负则打印警告;didSet在赋值后比较新旧值,根据变化输出相应信息。在实例`c`中,`radius`从-5变为0时,输出“Input value is negative.”和“The circle gets smaller.”;从0变为10时,输出“Input value is normal.”和“The circle gets larger.”。
223 4
Swift开发——属性检查器
|
6月前
|
人工智能 安全 架构师
修复来自开源和遗留程序的旧的、不安全的代码的三种方法
修复来自开源和遗留程序的旧的、不安全的代码的三种方法
|
7月前
|
C#
C# 三层级架构问题之 能加载文件或程序集或它的某一个依赖项。系统找不到指定的文件
C# 三层级架构问题之 能加载文件或程序集或它的某一个依赖项。系统找不到指定的文件
87 0
|
缓存 小程序 API
小程序:浅谈小程序更新机制,发版后多久能全覆盖
小程序:浅谈小程序更新机制,发版后多久能全覆盖
464 0
|
运维 监控 Cloud Native
移除 Staging 环境,加快部署过程
来自 Squeaky 的 Lewis Monteith 在一篇介绍公司部署方案的博文中详细描述了他们在 Staging 环境中发现的几个问题:
275 0
|
XML 搜索推荐 Java
系统配置自动装载机制 - 分布式开发
系统配置自动装载机制 - 分布式开发
115 0
系统配置自动装载机制 - 分布式开发