根据元数据包,netstandard库的应用含义是什么?

时间:2017-03-22 09:05:00

标签: nuget .net-core .net-standard

假设我有一个我想要定位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.3部分中定位frameworks,并明确依赖System.Runtime.Numerics,例如版本4.0.1。我创建的nuget包将列出该依赖项。

在基于csproj的dotnet工具的勇敢新世界中(我使用命令行工具的v1.0.1),在定位时,implicit metapackage package referenceNETStandard.Library 1.6.1 netstandard1.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软件包确切地说明了它的依赖性。直观地说,这感觉像是一个更精简的&#34;封装

那么我图书馆的消费者的确切区别是什么?如果有人试图在UWP应用程序中使用它,那么第二个,&#34;修剪&#34;依赖形式意味着生成的应用程序会更小?

通过不清楚地记录DisableImplicitFrameworkReferences(据我所见;我读到它in an issue)并在创建项目时将隐式依赖作为默认值,Microsoft是鼓励用户只依赖于元数据包 - 但是当我制作类库包时,我怎么能确定它没有缺点?

3 个答案:

答案 0 :(得分:75)

过去,我们已经向开发人员提出了不参考元的建议 来自NuGet包的包(NETStandard.Library),而是引用 单个包,例如System.RuntimeSystem.Collections。该 理由是我们认为元包是一堆的简写 这些包是.NET平台的实际原子构建块。该 假设是:我们最终可能会创建另一个.NET平台 支持其中一些原子块,但不是全部。因此,您引用的包越少,您的便携性就越高。还有人担心我们的工具如何处理大包图。

继续前进,我们将简化这一点:

  1. .NET Standard是一个原子构建块。换句话说,新平台 不允许将.NET标准化 - 他们必须实现所有这些。

  2. 我们正在不再使用套餐来描述我们的平台, 包括.NET Standard。

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

    但是,现在我们的工具仍将在参考中燃烧 NETStandard.Library。也没有任何伤害,它只会变成 多余的前进。

    我将更新.NET Standard repo上的FAQ以包含此问题。

    更新:此问题现在为part of the FAQ

答案 1 :(得分:18)

团队过去常常建议弄清楚最薄的包裹是什么。他们不再这样做了,建议人们只需引入NETStandard.Library(在SDK风格的项目中,这将自动完成)。

我从来没有得到一个完全直截了当的答案,为什么那样,所以请允许我做一些有根据的猜测。

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

通过将netstandard库或netcoreapp应用程序的元定义推送到适当的NuGet包中,他们不必在定义中构建任何特殊知识这些东西就像Visual Studio(或dotnet new)看到的那样。

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

如果您愿意,没有什么可以阻止您做出选择性的事情。我相信你会发现你几乎是唯一一个这样做的人,这也违背了目的(因为假设每个人都带来NETStandard.LibraryMicrosoft.NETCore.App)。

答案 2 :(得分:8)

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

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

这些API的实现由目标平台提供,例如.NET Core,Mono或.NET Framework。它们随平台一起发布,因为它们是平台的重要组成部分。所以没有必要指定一个较小的依赖集 - 一切都已经存在,你不会改变它。

NETStandard.Library包提供了这些参考程序集。令人困惑的一点是版本号 - 软件包是版本1.6.1,但这并不意味着&#34; .NET Standard 1.6&#34;。它只是包的版本。

您定位的.NET标准版本来自您在项目中指定的目标框架。

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

NETStandard.Library包会根据您的目标框架名字对象为您提供一组不同的引用程序集(为简洁起见,我简化了lib\netstandard1.0lib\netstandard1.1和{ {3}})。因此,如果您的项目定位netstandard1.3,您将获得1.3参考装配。如果您定位netstandard1.6,您将获得1.6参考装配。

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

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

  

请注意dependency groups,但它目前还没有修剪,并会发布所有程序集。这将是dotnet publish will create a standalone application,所以再次修剪图书馆中的依赖关系在这里没有帮助。

我可以想象可能有助于删除NETStandard.Library引用的唯一地方是,如果您的目标是不支持.NET标准的平台,那么您可以从.NET标准中找到一个包,其中所有传递依赖项都可以在目标平台上运行。我怀疑没有多少套餐可以满足这个要求。