取决于元包的netstandard库对应用程序有何影响?


100

假设我有一个要针对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,我将以netstandard1.3frameworks节为目标,并明确依赖于System.Runtime.Numerics例如4.0.1版。我创建的nuget包将仅列出该依赖项。

在基于csproj的dotnet工具的崭新世界(我正在使用命令行工具的v1.0.1),在目标定位时有一个隐式的metapackage包引用。这意味着我的项目文件非常小,因为它不需要显式依赖:NETStandard.Library 1.6.1netstandard1.3

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

...但是生成的nuget包依赖于NETStandard.Library,这表明要使用我的小图书馆,您需要那里的一切

事实证明,我可以使用禁用该功能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软件包确切说明了它所依赖的内容。凭直觉,这感觉像是“精简”的程序包。

那么,对于我的图书馆的消费者来说,到底有什么区别呢?如果有人尝试在UWP应用程序中使用它,那么第二种“修剪”的依赖关系形式是否意味着生成的应用程序会更小?

通过不DisableImplicitFrameworkReferences清晰地记录文档(据我所知;我已阅读一个问题),并通过在创建项目时将隐式依赖关系设置为默认值,Microsoft 鼓励用户仅依赖元包-但我该怎么做?确定在生成类库包时没有缺点吗?


3
应当指出,正在对依赖项进行微调。当前,Hello World!自包含应用程序的大小减小到<10MB。
ABarney

与经典.NET Framework C#hello-world项目的< 20KB大小相比,@ ABarney 10MB仍然太多了。

Answers:


76

过去,我们曾向开发人员建议不要引用NETStandard.LibraryNuGet包中的meta包(),而应引用单个包,例如System.RuntimeSystem.Collections。理由是我们认为meta包是一堆打包的简写,这些包是.NET平台的实际基本组成部分。假设是:我们可能最终会创建另一个.NET平台,该平台仅支持其中一些原子块,但不支持所有原子块。因此,您引用的软件包越少,您将越容易携带。也有人担心我们的工具如何处理大型包装图。

展望未来,我们将简化此过程:

  1. .NET Standard是一个基本的构建块。换句话说,新平台不允许子集.NET标准-它们必须实现所有标准。

  2. 我们不再使用软件包来描述我们的平台,包括.NET Standard。

这意味着,您不再需要引用任何适用于.NET Standard的NuGet软件包。您用lib文件夹表达了依赖性,这完全适用于所有其他.NET平台,尤其是.NET Framework。

但是,现在我们的工具仍然会在参考资料中使用 NETStandard.Library。这也没有害处,它将向前发展变得多余。

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

更新:此问题现在是常见问题解答的一部分


9
谢谢-这很有意义。我认为我有些困惑,因为在project.json世界中,即使软件包在逻辑上是我要针对的框架的一部分(例如netstandard1.3的System.Runtime.Numerics),我也必须添加依赖项-所以我认为NETStandard.Library是确实将它们作为依赖项加入。
乔恩·斯基特

2
笨蛋 我喜欢引用包的想法,因为感觉我只能引用我想要的内容,而不是整个“厨房水槽”。也许我没有考虑正确?
Nate Barbettini

3
您不一定会以错误的方式思考它,但问题是您为什么在乎。重要的是要了解平台不是无限可组合的。当您在共享框架环境(.NET Framework,Mono,.NET Core)中运行时,所有这些位仍然存在。如果您构建一个独立的应用程序(Xamarin,带有链接器的Mono / .NET Core),我们可以根据您的实际使用情况自动进行调整。因此,无论哪种方式,您都不会因不引用较小的块而丢失任何内容。
Immo Landwerth,2017年

3
如何让编译器强制执行规则,例如通过不允许该程序包阻止开发人员在业务逻辑项目中发出http请求,这会浪费精力吗?
David Ferretti

不一定,但是您如何执行它,即是什么阻止开发人员添加引用?我会编写一个在构建时注入的分析器,以强制执行层规则并在构建计算机上导致错误。
Immo Landwerth

19

该团队曾经建议找出最薄的包装盒。他们不再这样做,而是建议人们只使用NETStandard.Library(对于SDK样式的项目,这将自动为您完成)。

关于这是为什么,我从未得到一个完全简单的答案,所以请允许我做出一些有根据的猜测。

主要原因可能是因为它们允许它们隐藏依赖库版本的差异,否则在更改目标框架时可能需要这些差异来跟踪自己。使用基于SDK的项目文件,它也是一个更加用户友好的系统,因为坦率地说,您不需要任何引用即可获得相当不错的平台块(就像您以前在Desktop-land中使用默认引用一样,尤其是mscorlib )。

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

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

如果您选择的话,没有什么可以阻止您变得非常挑剔。我相信您会发现自己几乎是唯一一个这样做的人,这也违背了目标(因为假定每个人都在引入NETStandard.LibraryMicrosoft.NETCore.App)。


6
我同意,一旦存在多个依赖关系(如果其中任何一个引入),那肯定会破坏目的NETStandard.Library。当然,这有点自我实现...如果依赖NETStandard.LibraryNoda Time,这意味着在Noda Time之上构建的任何其他库都没有理由减少依赖关系,等等。现在很容易选择(Noda Time是朝着2.0迈进),然后在建立约定后稍稍放松一下-我认为从选择性更改为基于lib的更改将是不间断的,但事实并非如此。
乔恩·斯基特

8

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

.NET标准库是一种规范,是您参考的一组参考程序集,它提供了一组API,这些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版的程序包。但更重要的是,您的项目文件应为target netstandard1.3

NETStandard.Library包会给你一组不同的取决于你的目标框架名字对象的引用程序集(我简化为简洁,但想想lib\netstandard1.0lib\netstandard1.1依赖性组)。因此,如果您的项目目标是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未引入任何其他新应用。

请注意,这dotnet publish将创建一个独立的应用程序,但当前不会进行修剪,并将发布所有程序集。这将通过工具自动处理,因此,再次修剪库中的依赖项将无济于事。

我能想象到的唯一可能会删除NETStandard.Library引用的地方是,如果您针对的是不支持.NET Standard的平台,并且可以从.NET Standard中找到一个包,可以在其中运行所有传递依赖项在您的目标平台上。我怀疑没有多少软件包能满足要求。


如果dotnet publish对特定的运行时执行操作,它将引入所有依赖项,包括dotnet.exe(或其等效的Linux / OS X)。那时,那应该是一个完全独立的部署。查看单元测试项目的结果:gist.github.com/bradwilson/6cc5a8fdfa18230aa6c99b851fb85c01
Brad Wilson

4
我认为最后一段正是问题所在……如果不是问题,为什么我们根本需要不同版本的netstandard1.x?如果每个平台都在netstandard1.6中包含所有内容,为什么还要 netstandard1.0作为一个概念?这对我来说是令人困惑的部分。
乔恩·斯基特

1
并且支持.NET Standard的平台列表不包括许多Unity平台中的任何一个。
–citritmatt

1
(顺便说一句,您的耐心深表谢意。我真的希望这一切都有意义,并且这将对许多开发人员有所帮助...)
Jon Skeet

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.