依赖元包的 netstandard 库对应用有何影响?

What are the application implications of a netstandard library depending on a metapackage?

假设我有一个 class 库,我想以 netstandard1.3 为目标,但也使用 BigInteger。这是一个简单的例子 - 唯一的源文件是 Adder.cs:

using System;
using System.Numerics;

namespace Calculator
{
    public class Adder
    {
        public static BigInteger Add(int x, int y)
            => new BigInteger(x) + new BigInteger(y);            
    }
}

回到 project.json 的世界,我会在 frameworks 部分中以 netstandard1.3 为目标,并明确依赖 System.Runtime.Numerics,例如版本 4.0.1。我创建的 nuget 包将仅列出该依赖项。

在基于 csproj 的 dotnet 工具的美丽新世界中(我使用的是 v1.0.1 命令行工具)当目标 [=16= 时,有一个 implicit metapackage package referenceNETStandard.Library 1.6.1 ].这意味着我的项目文件非常小,因为它不需要显式依赖:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard1.3</TargetFramework>
  </PropertyGroup>
</Project>

...但是生成的 nuget 包依赖于 NETStandard.Library,这表明为了使用我的小型库,你需要 everything

事实证明我可以使用 DisableImplicitFrameworkReferences 禁用该功能,然后再次手动添加依赖项:

<Project Sdk="Microsoft.NET.Sdk">    
  <PropertyGroup>
    <TargetFramework>netstandard1.3</TargetFramework>
    <DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="System.Runtime.Numerics" Version="4.0.1" />
  </ItemGroup>    
</Project>

现在我的 NuGet 包准确说明了它所依赖的内容。直觉上,这感觉像是一个 "leaner" 包。

那么对于我的图书馆的消费者来说,确切的区别是什么?如果有人试图在 UWP 应用程序中使用它,第二种 "trimmed" 依赖形式是否意味着生成的应用程序会更小?

由于没有清楚地记录 DisableImplicitFrameworkReferences(据我所知;我读到了它 in an issue)并且在创建项目时将隐式依赖设为默认值,Microsoft 鼓励 用户只依赖于元包 - 但我如何确保在生成 class 库包时没有缺点?

该团队曾经建议弄清楚最薄的封装集是什么。他们不再这样做,并建议人们只引入 NETStandard.Library(对于 SDK 样式的项目,这将自动为您完成)。

关于为什么会这样,我从来没有得到一个完全直接的答案,所以请允许我做一些有根据的猜测。

主要原因可能是它允许他们隐藏依赖库的版本差异,否则您在更改目标框架时需要自己跟踪。它也是一个更加用户友好的系统,具有基于 SDK 的项目文件,因为坦率地说,您不需要任何引用来获得平台的大部分内容(就像您过去使用桌面领域的默认引用一样,尤其是 mscorlib ).

通过将 netstandard 库或 netcoreapp 应用程序的元定义推送到适当的 NuGet 包中,他们不必在其中构建任何特殊知识Visual Studio(或dotnet new)对这些事物的定义看到了它们。

在发布期间可以使用静态分析来限制传送的 DLL,这是他们今天在为 UWP 进行本机编译时所做的事情(尽管有一些警告)。他们今天没有为 .NET Core 这样做,但我认为这是他们考虑过的优化(以及支持本机代码)。

如果您愿意,没有什么能阻止您非常挑剔。我相信你会发现你几乎是唯一一个这样做的人,这也违背了目的(因为假设每个人都在引入 NETStandard.LibraryMicrosoft.NETCore.App)。

您不需要禁用隐式引用。该库能够 运行 的所有平台都已经具有 NETStandard.Library 依赖项需要的程序集。

.NET 标准库是一个规范,一组参考程序集,您可以根据这些程序集编译,提供一组 API 保证存在于一组已知的平台和平台版本上,例如 .NET Core 或 .NET Framework。它不是这些程序集的实现,只是足以让编译器成功构建代码的 API 形状。

这些 API 的实现由目标平台提供,例如 .NET Core、Mono 或 .NET Framework。它们与平台一起发布,因为它们是平台的重要组成部分。因此无需指定更小的依赖集 - 一切都已经存在,您不会更改它。

NETStandard.Library 包提供了这些参考程序集。混淆的一点是版本号——包是 1.6.1 版,但这并不意味着“.NET Standard 1.6”。只是包的版本。

您所针对的 .NET Standard 版本来自您在项目中指定的目标框架。

如果您正在创建一个库并希望它在 .NET Standard 1.3 上 运行,您将引用 NETStandard.Library 包,当前版本为 1.6.1。但更重要的是,您的项目文件将以 netstandard1.3.

为目标

NETStandard.Library 包将为您提供一组不同的参考程序集,具体取决于您的目标框架名称(为简洁起见,我进行了简化,但认为 lib\netstandard1.0lib\netstandard1.1dependency groups).因此,如果您的项目面向 netstandard1.3,您将获得 1.3 参考程序集。如果您以 netstandard1.6 为目标,您将获得 1.6 参考程序集。

如果您正在创建应用程序,则不能以 .NET Standard 为目标。这没有意义 - 你不能 运行 规范。相反,您可以针对具体平台,例如 net452netcoreapp1.1。 NuGet 知道这些平台与 netstandard 目标框架名字对象之间的映射,因此知道哪些 lib\netstandardX.X 文件夹与您的目标平台兼容。它还知道 NETStandard.Library 的依赖项已被目标平台满足,因此不会引入任何其他程序集。

同样,在创建独立的 .NET Core 应用程序时,.NET Standard 实现程序集会随您的应用程序一起复制。对 NETStandard.Library 的引用不会引入任何其他新应用。

Note that , but it won't doesn't currently do trimming, and will publish all assemblies. This will be , so again, trimming dependencies in your library won't help here.

我能想到的唯一 可能 有助于删除 NETStandard.Library 引用的地方是,如果您的目标平台不支持 .NET 标准,并且您可以从 .NET Standard 中找到一个包,其中所有传递依赖项都可以 运行 在您的目标平台上。我怀疑符合该要求的包裹并不多。

过去,我们建议开发者不要引用元数据 NuGet 包中的包 (NETStandard.Library) 而不是引用 单独的包,例如 System.RuntimeSystem.Collections。这 基本原理是我们将元包视为一堆 shorthand .NET 平台的实际原子构建块的包。这 假设是:我们最终可能会创建另一个 .NET 平台,它只 支持其中一些原子块,但不是全部。因此,您引用的包越少,您的便携性就越高。还有人担心我们的工具如何处理大型包图。

接下来,我们将对此进行简化:

  1. .NET Standard 是一个原子构建块。也就是说,新平台 不允许对 .NET Standard 进行子集化——他们必须实现所有标准。

  2. 我们将不再使用包来描述我们的平台, 包括 .NET 标准。

这意味着,您不必为 .NET Standard 引用任何 NuGet 包 了。您表达了对 lib 文件夹的依赖,这正是 它适用于所有其他 .NET 平台,尤其是 .NET Framework。

但是,现在我们的工具仍然会在对 NETStandard.Library。这也没有坏处,它只会变成 多余的前进。

我将更新 .NET Standard 存储库中的 FAQ 以包含此问题。

更新: 这个问题现在part of the FAQ.