Visual Studio 2010 中的多重目标 Visual Basic 应用程序


 在 Visual Studio 2008 之前,编写面向不同版本的 Microsoft .NET Framework 的应用程序需要安装不同版本的 Visual Studio 开发环境。每个版本的 Visual Studio 都提供了不同的开发人员体验,并会占用大量磁盘空间。而且,每个版本的 Visual Studio 的项目文件格式也各不相同。结果就是当您开发面向不同版本的 .NET Framework 的项目组件时,您会得到多个版本的项目文件或解决方案。

  Visual Studio 2008 是第一个在单个 IDE 中完全支持多重目标的版本,允许开发人员使用一个版本的 Visual Studio 编写面向不同版本的 .NET Framework(2.0、3.0 和 3.5)的应用程序。结果如何?开发人员可获得一致的使用体验,同时减少磁盘空间需求。

  Visual Studio 2008 能够实现多重目标是因为每个可用的框架都使用了相同的基础 CLR 2.0。而且,每个版本的框架都构建在 .NET Framework 2.0 的基础上,并通过使用被引用程序集来提供其他功能。最终,所有框架都使用 .NET Framework 3.5 命令行 Visual Basic 编译器 (vbc.exe)。

  本文将讨论 3.5 和 4 编译器,即分别包含在 .NET Framework 3.5 和 4 中的编译器。3.5 编译器是随 Visual Studio 2008 和 Visual Basic 9 提供的版本,而 4 编译器是随 Visual Studio 2010 和 Visual Basic 10 提供的版本。

  让我们看一下当前多重目标在 Visual Studio 中的工作原理,并说明应该如何在项目中实现多重目标。

  Visual Studio 中的多重目标

  在 Visual Studio 2008 中,更改所需的目标框架很简单,只需从项目属性中的下拉列表选择目标即可,如图 1 所示。这可以添加或删除每个框架版本所需的特定引用,并轻松地更改框架。


图 1 在 Visual Studio 2008 中更改所需的目标框架

  对于命令行编译,只需更改所用的引用程序集即可。

  但在 Visual Studio 2010 中有了一些重大变更。新的 .NET Framework 4 引入了新版本的 CLR。这意味着 Visual Studio 2008 中采用的方法不能用于 Visual Studio 2010。因此,Visual Studio 2010 使用版本 4 的编译器用于所有的多重目标,即使目标是旧版本的 .NET Framework。这就允许在向下定向时使用很多新的语言功能,并提供大为简化的开发体验。  

  但是,可以针对低级目标使用 Visual Studio 2010 功能的一个缺点是,如果用于之前版本的 Visual Studio,源文件可能不是设计时兼容的。如果您要共享使用不同版本的 Visual Studio 构建且面向不同版本的 .NET Framework 的项目的源代码,就会遇到问题。

  如果项目始终保持在 Visual Studio 2010 中,用于所有设计时工作,则您将获得更好的体验。您只需使用 Visual Studio 2010 和 .NET Framework 3.5 SP1,即可生成可在 .NET Framework 2.0 及以后版本中使用的程序集。

  设计时兼容性

  现在让我们来看一个设计时兼容性陷阱的示例。图 2 中的代码使用了隐式行继续符和自动实现的属性功能,这两者都是在 Visual Studio 2010 中引入的。使用 Visual Studio 2010 进行编译时,这段代码可以编译为面向所有 2.0 以上版本的框架。因此生成的程序集是运行时兼容的。


图 2 使用可在低级目标中工作的新语言功能

  但是,同样是这个源代码文件,使用版本 3.5 或 2.0 的编译器进行编译后,您将得到图 3 中所示的错误。


图 3 来自 Visual Studio 2010 的源代码与 Visual Studio 2008 不是设计时兼容的

  发生这个问题是由于早期版本的编译器完全不了解这些功能,会将其视为无效代码。因此源文件不是设计时兼容的。若要使其成为设计时兼容的,您必须只使用在 3.5 编译器中可用的功能。 

  设计时兼容性对于 Web 项目同样有意义。很多 Web 项目的编译发生在服务器上,而服务器肯定会使用其上安装的目标框架编译器来编译页面。如果您的 Web 页面是在 Visual Basic 中编写且面向 3.5 编译器的,则页面将在服务器上使用版本 3.5 的 Visual Basic 编译器 (vbc.exe) 进行编译。使用新的 Visual Studio 2010 语言功能必将导致失败,因为 3.5 编译器对它们一无所知。

  对于在 Visual Studio 2010 中开发且使用版本 4 编译器的代码,您需要通过某种方法在编译时识别此要求,以防止 Web 页面部署到服务器时发生意外错误。为此您可以使用 /langversion 开关。此开关在开发 Web 项目时使用,可以生成有关新版语言语法功能与早期框架编译器不兼容的错误。构建 ASP.NET 项目时,如果您的代码使用新的 Visual Studio 2010 功能但您面向的是早期版本的框架,则在内部使用此开关可以生成错误。

  尽管在默认情况下,/langversion 开关不会用于其他类型的项目,但如果您要验证源代码与旧版本的 Visual Studio 是否是设计时兼容的,则此开关会很有用。

  Visual Studio 2010 IDE 中的多重目标

  Visual Studio 2010 IDE 中的多重目标用户体验几乎与 Visual Studio 2008 中的完全一致,它仍然从项目属性内部进行控制,但在默认安装中,您可能不会看到早期目标框架。为了减小安装大小,Visual Studio 团队决定在 Visual Studio 2010 的默认安装中不提供 3.5 框架。这一变化意味着您在“目标框架”下拉列表或“新建项目”对话框中看不到这些框架选项。

  若要添加这些框架,您需要安装 .NET Framework 3.5 SP1。您可以从 IDE 执行此操作。在“新建项目”对话框的上部,您将看到下拉菜单,可以选择目标框架。如果只安装了 .NET Framework 4,则此菜单包含一个链接,用于下载更多框架。但如果您安装了其他版本,则在下拉菜单中只能看到 .NET Framework 3.5 SP1,因为 Visual Studio 在这里只能识别已安装的 .NET Framework 3.5 SP1。

  另一项更改与客户端配置文件有关。这些配置文件在 .NET Framework 3.5 SP1 中引入,可让应用程序使用精简版的框架,从而能够改进部署,因为不再要求包括服务器端的框架组件,例如 ASP.NET。这些配置文件在 3.5 和 4 框架目标中都可用。

  因此,各种项目类型的默认配置文件都已更改。客户端项目类型(Windows、Console、Office 和 Windows Presentation Foundation (WPF) 应用程序)默认情况下都使用客户端配置文件。但是,对于 Web 应用程序来说,默认的配置文件是“完全”配置文件,因为要引用未使用客户端配置文件部署的库,例如 System.Web。

  类库默认情况下也采用完全配置文件,但如果您只依赖使用客户端配置文件部署的引用,则可以很轻松地更改回客户端配置文件。如果您的类库设置为完全配置文件,然后在使用客户端配置文件的项目中使用,只要该库并不依赖不属于客户端框架程序集的引用,该类库就可以正常工作。

  默认情况下,添加到类库项目类型的引用都不要求完全配置文件。但是,由于它们随应用程序一起部署,因此应用程序部署配置文件是确保应用程序正常运行的重要设置。如果您的库依赖客户端范围之外的引用,则库和使用该库的应用程序都需要使用完全配置文件。

  使用命令行编译器实现多重目标

  版本 4 编译器有许多命令行开关,但遗憾的是,没有哪个开关可以控制目标框架,因此有必要稍稍了解这些开关以及它们的工作原理。

  如果安装了 .NET Framework 4,则可以使用 vbc.exe 构建面向早期版本的框架的应用程序,而不需要在构建计算机上安装 Visual Studio。直接调用命令行编译器的构建脚本常用于大型开发环境。如果您从命令行定向到早期版本,则要求使用您面向的早期框架版本安装文件,因此最佳方案是在计算机上同时安装 .NET Framework 3.5 SP1 和 .NET Framework 4。

  考虑到这一点,图 4 详细介绍了一些用于多重目标的潜在开关。

  图 4 用于控制多重目标的命令行构建开关

开关 说明
langversion 为使用不符合特定语言版本的功能的源代码提供错误。(9.0 与 .NET Framework 3.5 及以上版本的目标相关;10 与 .NET Framework 4 目标相关。)这实际上并不确定所用的目标框架或 CLR,但允许 Web 项目识别在向下定向方案中使用的 Visual Studio 2010 功能。
vbruntime 尽管有不同版本的 Microsoft.VisualBasic 可用于 .NET Framework 4,但简单地尝试指定版本 2.0 的 Microsoft.VisualBasic.dll 不能解决问题,而且会导致程序集依赖于版本 4 的 NetFX。
nostdlib 阻止向程序集中添加对 system.dll 的标准引用。尽管可以在 2.0 框架中使用此选项和对 system.dll 版本的引用,但结果仍是版本 4 的程序集。
sdkpath 如果 vbruntime 开关没有指定使用 MSCorLib.dll 还是 Microsoft.VisualBasic.dll,则此选项就是一个关键选项,可指定使用哪个版本的 MSCorLib.dll 和 Microsoft.VisualBasic.dll。但是,这并不是您通常在引用列表中看到的显式引用。相反,编译器将其包含在标准引用中。当您需要版本 2.0 而不是版本 4 的 MSCorLib 时,需要在解决方案中添加它以现实多重目标。
noconfig 使编译器避免加入 vbc.rsp 文件中包含的默认引用、导入和开关,否则就将使用这些内容。

  这个表格简要介绍了各个开关,但为了实际创建向下定向的编译,您将需要组合使用多个开关,因为没有一个单独的多重目标开关。对于版本 3.5 的目标,最重要的开关是 sdkpath,您可以用它来指定版本 2.0 的 MSCorlib。然后确保您的引用指向正确版本的 System.dll、System.core.dll 和其他早期目标框架程序集。(这些文件可以在 %programfiles%\Reference Assemblies\Microsoft\Framework\v3.5 文件夹中找到。)

  您需要指定 noconfig 开关以避免使用版本 4 的 vbc.rsp(包含了默认的编译设置)中的默认开关。如果不添加这个重要的开关,编译程序将添加那些默认的版本 4 引用、导入等等。

  多重目标命令行编译可通过示例进行最好的演示。在这里,我只是面向 .NET Framework 3.5 编译一个简单的源文件 test.vb:

  vbc.exe /noconfig /sdkpath:D:\WINDOWS\Microsoft.NET\Framework\v2.0.50727 /r:"D:\Program Files\ReferenceAssemblies\Microsoft\Framework\v3.5\System.Core.dll" d:\school\test.vb  /out:\school\test.exe

  当您了解编译 3.5 程序集的开关后,面向 2.0 只需要删除一些 3.5 框架所需的引用,例如 system.core.dll。sdkpath 和 noconfig 开关保持不变:

  vbc.exe /noconfig /sdkpath:D:\WINDOWS\Microsoft.NET\Framework\v2.0.50727 d:\school\test.vb /out:\school\test.exe

  编译二进制文件之后,您可以使用 MSIL Disassembler (Ildasm.exe) 或 .NET Reflector 等工具来查看所使用的引用的版本。这可以让您确定可执行文件是否在所需的目标框架上运行。

  客户端配置文件和多重目标解决方案

  在前文中,我提到客户端配置文件是大多数项目类型的默认设置。部署这样的应用程序时,将安装更精简的框架。在部署期间,您将看到还会部署命令行编译器。该编译器的版本与使用完全框架部署时相同,但是尝试使用客户端配置文件来编译简单应用程序时,可能会遇到陷阱。

  在客户端框架计算机上使用此命令可能会失败,因为客户端框架并未随附包含默认引用的 vbc.rsp:

  vbc.exe test.vb /out: test.exe

  您必须指定 vbc.rsp 文件中通常会包含的所有引用和导入语句,或者自行创建这些语句。  

  在客户端框架上编译 Visual Basic 应用程序最少需要以下开关:

/r:System.dll
/imports:System
/imports:Microsoft.VisualBasic

  加入这些开关您就可以编译基本的 Visual Basic 应用程序。但是,您应该在安装了完全框架的计算机上编译应用程序。

  多重目标解决方案(使用 .NET Framework 3.5 构建的类库用在面向 .NET Framework 4 的客户端应用程序中)是受支持的,但有一些需要注意的地方。在 Visual Studio 2010 IDE 中,如果您使用项目引用并且熟悉这种体验,则您仍将获得这种体验,前提是项目引用中的目标框架使用相同版本的 MSCorlib。图 5 显示了 MSCorlib 版本和受支持的框架版本。

  图 5 MSCorlib 和框架版本兼容性

MSCorlib 版本 支持的框架 配置文件
2.0 2.0、3.0、3.5 客户端和完全配置文件
4.0 4 客户端和完全配置文件

  如果您在 .NET Framework 3.5 应用程序中使用面向 MSCorlib 2.0 的类库,您仍可以使用项目引用。同样,由 .NET Framework 4 客户端配置文件 Windows 应用程序引用的 .NET Framework 4 完全配置文件类库可以拥有对该库的项目引用。

  但是,如果您使用项目到项目的引用,而这些项目中使用的 MSCorlib 版本不同,则项目引用将被转换为文件引用。这意味着在您更正错误时需要手动重建解决方案。如果您曾经处理过拥有多个分别用 C# 和 Visual Basic 编写的引用项目的解决方案,则会熟悉这种经验。您会失去一些项目引用所具备的方便功能,例如在项目间重命名以及自动的后台编译。

  在编译期间,IDE 在一定程度上为您屏蔽了后台执行的操作,但并不是每个人都从 IDE 构建程序。如果对目标框架进行更改,使两个引用所使用的框架具有同一版本的 MSCorlib,则文件引用将自动变回项目引用,因此这并不是真正的文件引用。

  如果您在版本 4 应用程序中使用向下定向的 (3.5) 类库,会发生什么呢?类库实际将使用 .NET Framework 4。需要大量测试以确保此方案运行时不出现问题。但是,在 3.5 框架应用程序中使用 4.0 框架类库不受支持,并会造成使用 Visual Studio 或 MSBuild 构建时发生编译时错误。若要在面向 3.5 框架的应用程序中使用 4.0 框架类库,您可能需要将类库向下定向到 .NET Framework 3.5。

  请记住,由于可以在向下定向的方案中使用 Visual Studio 2010 语言功能,因此将类库定向到 .NET Framework 3.5 应该不是大问题。图 6 总结了您可以在向下定向的项目中使用的新功能。

  图 6 向下定向方案中的新 Visual Studio 功能

语言功能 是否能用在向下定向方案中
集合初始值设定项
数组初始值设定项
自动实现的属性
隐式行继续符
语句 Lambda
无 PIA 不能
动态互操作 不能
协变/逆变 部分支持

  PIA 和互操作

  若要使用 .NET Framework 对 Microsoft Office 对象模型进行编程,需要使用主互操作程序集 (PIA)。PIA 必须部署到用户计算机上,而且通常会很大,因此部署它们是一项费力的工作。

  新的类型嵌入功能使得用户计算机上没有 PIA 也可部署这些应用程序。做到这一点的方式是通过生成嵌入式互操作类型,来执行对 COM 库的直接互操作调用。编译器会对这些类型做出注释,以便 CLR 平等对待所有嵌入式互操作类型示例。编译器不会将 PIA 中的所有类型都复制到您的程序集中,而只是复制您实际使用的类型。

  此功能在低于 .NET Framework 4 的向下定向方案中不受支持。在使用 Visual Studio IDE 时,这可能不像在向下定向的方案中将引用嵌入式互操作属性设置为 true 以便使用普通引用那么明显。IDE 功能的用户体验是程序集将继续构建,但会还原为标准引用的行为,这将要求部署 PIA。

  在命令行中,通常使用 /reference 开关来添加引用。对于嵌入,则要使用 /link 开关。在向下定向的方案中尝试使用 /link 开关会导致编译错误。

  以下是来自 Word 互操作程序集的命令行嵌入式类型:

  D:\Windows\Microsoft.NET\Framework\v4.0.30128\Vbc.exe /imports:Microsoft.VisualBasic,System /link:"D:\Program Files\Microsoft Visual Studio 10.0\Visual Studio Tools for Office\PIA\Office14\Microsoft.Office.Interop.Word.dll" /reference:"D:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\Profile\Client\System.Core.dll","D:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\Profile\Client\System.dll" /out:ConsoleApplication16.exe /target:exe Module1.vb

  这种行为很重要,因为在默认情况下,添加到 Visual Studio 2010 项目中的 COM 引用会将嵌入互操作属性设置为 true。因此更改目标框架不应该导致其他错误,而会在可能时提供嵌入式互操作类型的优势。

  向下定向方案中不受支持的另一项 Visual Studio 2010 新功能是动态互操作,因为在 Visual Studio 2010 之前,动态语言运行时 (DLR) 还不存在。

  其他问题

  支持协变和逆变,是为了在用户定义的接口中使用。但是,针对低级目标的基类库 (BCL) 接口并未改变,因此不支持使用这些基类所提供的功能。

  如果您在 Visual Studio 2010 中打开在早期版本的 Visual Studio 中创建的项目或解决方案,您将看到标准的升级对话框。Visual Studio 会对项目或解决方案文件做出必要的更改,以便在 Visual Studio 2010 中使用。但是,升级文件时的两项操作会影响多重目标。

  如果您已安装 .NET Framework 3.5 SP1,升级对话框将允许项目或解决方案文件升级到 Visual Studio 2010,但为项目指定的目标框架保持不变。因此如果您升级面向 .NET Framework 3.5 的应用程序,升级之后该程序应该仍旧面向 3.5 框架。

  如果您未安装 .NET Framework 3.5 SP1,则无法正确构建多重目标,因为您需要版本 2.0 的 MSCorlib 和引用程序集。对话框将提供选项,让您选择更改为面向版本 4 框架,或者不升级项目。这种情况下的最佳选择是取消升级,安装 .NET Framework 3.5 SP1,然后重复该过程以再次升级项目。

  通过深入了解 Visual Studio 2010 中 Visual Basic 多重目标的实现细节,您应该可以编写代码,使用 IDE 或命令行生成可以部署到旧版本框架的程序集,同时充分利用 Visual Studio 2010 的一些新功能。尽管多重目标有一些需要注意的地方,您还是可以开发和部署不能立即升级到使用 .NET Framework 4 的应用程序。  


« 
» 
快速导航

Copyright © 2016 phpStudy | 豫ICP备2021030365号-3