何时以及为啥需要supportedRuntime 元素和sku 属性?

Posted

技术标签:

【中文标题】何时以及为啥需要supportedRuntime 元素和sku 属性?【英文标题】:When and why do I need the supportedRuntime element and sku attribute?何时以及为什么需要supportedRuntime 元素和sku 属性? 【发布时间】:2018-04-28 04:14:39 【问题描述】:

在大多数(如果不是全部)C#(以及 F# 和 VB)库和在 Visual Studio 中创建的可执行项目中,都有一个自动添加的 app.config 文件,用于指定运行时版本和目标框架名字对象 (TFM):

<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
. . .

即使完全没有 app.config 文件,编译器似乎总是会生成一个程序集级属性,如 ILDASM 所示:

.custom instance void [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = ( 01    // ....NETFramework
                                                                                                      ..    // ,Version=v4.6.1.
                                                                                      bytes snipped-> ..    // .T..FrameworkDis
                                                                                                      ..    // playName..NET Fr
                                                                                                      61  ) // amework 4.6.1

.csproj 文件确实指定了目标框架,我猜这是在构建期间将目标传递给编译器的地方。

如果没有配置文件中的&lt;startup&gt; 部分,可执行文件似乎运行得很好。 The documentation 解释了 什么 属性是什么意思,但是,多年来看到它们,我一直不明白 为什么 在配置文件中需要它们。不过,我主要处理的是 Windows 桌面应用程序。

This answer 明确指出“使编译为目标 .NET 4.0 的程序表现得像在更高版本上运行是不可能的”,相反,如果在较低版本上运行程序,我会感到非常惊讶框架也是可以的。

那么,在什么场景下,应用程序开发者需要在应用程序的.config文件中指定运行时的版本和TFM,是否必须总是复制编译器硬编码到二进制文件中的信息?乍一看,这个要求似乎违反直觉。


2018-06-29 更新:X-ref:我要求澄清 GitHub 问题 dotnet/docs#6234 中的文档。

【问题讨论】:

对我来说,设计似乎是“为未来保留一些东西”。硬编码到二进制文件中的信息是不可能更改的,但有时 Microsoft 可能需要向开发人员提供一种更改运行时行为的方法(我无法说出具体案例,但运行时版本相关的行为在 .NET Framework 中很常见),其中他们可以简单地修改 app.config 中的 SKU(在这种情况下,两者不再重复)。 【参考方案1】:

需要声明您的应用程序实际上与哪些框架版本兼容。假设我们有一个以 .NET Framework 4.7.2 为目标的应用程序,并尝试在仅安装了 .NET Framework 4.5 的机器上运行它。如果我们添加这个 app.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/></startup></configuration>

Windows 将显示一个很好的错误消息,要求安装所需的框架版本:

如果我们省略 app.config,Windows 将尝试运行它,然后应用程序将在第一次遇到特定于 .NET Framework 4.7.2 的功能时崩溃,并且在已安装的框架版本中不存在。

请注意,文档中说“此元素应由使用 .NET Framework 1.1 或更高版本构建的所有应用程序使用”具有误导性。它可能被解释为“此元素是应用程序在 .NET 1.1+ 上运行所必需的”,而实际上它仅意味着 .NET 1.1 更改了以前在 .NET 1.0 中使用的语法 @987654324 @ 句法。更多时候,应用程序运行不需要supportedRuntime,它只是为了漂亮。

supportedRuntime确实需要应用程序运行的一个常见情况是,当我们有面向 .NET 2.x-3.x 的应用程序并尝试在只有 4 个的机器上运行它时.x(例如,Windows 10 有 4.6+,但默认没有安装 .NET 2.x-3.x)。在这种情况下,如果 app.config 中没有supportedRuntime,应用程序将根本无法运行,即使 4.x 大部分与以前的版本兼容。添加&lt;supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" /&gt; 将解决此问题。


因此,总而言之,它不会复制程序集元数据中的信息,而是为 Windows 提供有关如何将应用程序与其兼容的框架版本连接的附加信息,以及如果不存在则要求用户安装哪个版本在目标机器上。

【讨论】:

“supportedRuntime 是 […] 应用程序运行所需要的,当我们有面向 .NET 2.x-3.x 的应用程序并尝试在只有 4.x 的机器上运行它时”--这是了不起的。看起来 app.config 中的属性 覆盖 程序集级属性(假设旧工具也嵌入了 TargetFrameworkAttribute)。下载提示的行为令人费解;看起来最初的 exe 加载过程(这对我来说真的很神秘)从 app.config 中选择目标版本,但忽略了同一程序集中的 TargetFrameworkAttribute。 有趣的设计决策……【参考方案2】:

targetFramework 属性主要确定用于编译目的的 .NET Framework。它还用于确定引用 .NET 库 (DLL) 的兼容性。但是,当您将 .NET 项目作为应用程序分发并将其部署到其他计算机上时,就会出现一个问题。问题是“如果目标计算机没有安装编译期间使用的 .NET Framework 版本会怎样?”。这就是 supportedRuntime 元素具有一定意义的地方。 supportedRuntime 元素列表中匹配的第一个版本将用于运行应用程序。如果 supportedRuntime 元素中的任何版本都与目标计算机上安装的版本不匹配,则将使用最新版本的框架来运行应用程序。

我希望这个解释能回答你的问题。

【讨论】:

以上是关于何时以及为啥需要supportedRuntime 元素和sku 属性?的主要内容,如果未能解决你的问题,请参考以下文章

为啥以及何时需要展平 JSON 对象?

为啥以及何时需要提供我自己的删除器?

为啥以及何时需要在 MongoDB 中重建索引?

为啥以及何时需要在 React 中绑定函数和事件处理程序?

何时以及为啥需要在 C++ 中使用 cin.ignore()?

为啥我们需要复制构造函数以及何时应该在 java 中使用复制构造函数