库是不是应该明确针对 .NET Core 3?

Posted

技术标签:

【中文标题】库是不是应该明确针对 .NET Core 3?【英文标题】:Should a library explicitly target .NET Core 3?库是否应该明确针对 .NET Core 3? 【发布时间】:2020-01-10 18:10:39 【问题描述】:

随着 .NET Standard 2.0 的发布,建议以 .NET Standard 2.0 为目标,即使您已经以 1.x 为目标。

https://docs.microsoft.com/en-us/dotnet/standard/net-standard:

但是,针对较低的 .NET Standard 版本会引入许多支持依赖项。如果您的项目以 .NET Standard 1.x 为目标,我们建议您也以 .NET Standard 2.0 为目标。这简化了在 .NET Standard 2.0 兼容框架上运行的库用户的依赖关系图,并减少了他们需要下载的包数量。

现在另一个重大变化即将来临! .NET Core 3,我看到 Microsoft 正在将 .NET Core 3 用于 Microsoft 软件包。

例如,Microsoft.Extensions.Logging 的目标是 .NET Standard 2.0 和 .NET Core 3 (.NETCoreApp 3.0):

我比较了 XML 文件,两个 API 看起来一样(可能不是比较它们的最佳方法)

现在的问题;)

作为依赖于 Microsoft.Extensions.Logging 并试图支持 .NET Core 3 的库维护者: 如果我不需要 .NET Core 3 的特定内容,我是否也应该以 .NET Core 3 为目标 - 还是仅 .NET Standard 2.0 就足够了?

【问题讨论】:

【参考方案1】:

简答

如果您不想使用 .NET Core 3 中的任何内容,或者不想提供任何 .NET Core 3 优化,则不必以 .NET Core 3 为目标。另一方面,双重定位不会花费您任何成本,并且可能允许您摆脱现在内置于 .NET Core 3 中的库引用。至少您可以摆脱现在的一些库引用运行时附带。

长答案

这完全取决于你在做什么,你想做什么。库必须以 .NET Core 3.0 为目标,因为它的依赖项将其包含在目标中。

例如,the source code 表明 Microsoft.Extensions.Logging 似乎没有任何 C# 8/.NET Core 3.0 特定代码。它以 3.0 为目标,因为它是那一波扩展的一部分,因此双重目标不需要任何修改。

另一方面,Config.Json 不必引用 System.Text.JsonSystem.Threading.Tasks.Extensions,因为它们是运行时的一部分。

  <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
    <Reference Include="System.Text.Json" />
    <Reference Include="System.Threading.Tasks.Extensions" />
  </ItemGroup>

其他好处

对于维护者,.NET Core 3.0/.NET Standard 2.1 提供了许多 健全的功能,例如:

可为空的引用类型。您将在自己的代码中避免大量 NRE。您可能还会发现很多隐藏的错误。 默认接口成员。当您将新成员添加到公共界面时,您不必担心会破坏用户的代码。 IAsyncEnumerable。无需再等待一堆异步操作的所有结果 switch 表达式和更强大的模式匹配和解构语法。

对于其中一些功能,您只能添加一些仅适用于 .NET Core 的方法。例如,ChannelReader class 在部分文件中添加单个 ReadAllAsync() 方法,该方法从通道读取项目并返回 IAsyncEnumerable&lt;&gt;,例如:

    public virtual async IAsyncEnumerable<T> ReadAllAsync([EnumeratorCancellation] CancellationToken cancellationToken = default)
    
        while (await WaitToReadAsync(cancellationToken).ConfigureAwait(false))
        
            while (TryRead(out T item))
            
                yield return item;
            
        
    

这是一个小但非常方便的补充。它允许您通过以下方式接收消息:

await foreach(var msg from reader.ReadAllAsync())

   ....

另一方面,NRT 甚至对 .NET Standard 2.0 也有帮助,因为它们可以帮助您在为 .NET Core 3.0 编译时捕获源代码中的可空性错误。

【讨论】:

但好处不是我还需要针对旧平台吗?我假设我不能将 c#8 语法用于(也针对).net 标准 2.0 @Julian 我发布了一个你如何可以的例子。在任何情况下,如果您想要以 .NET Core 3 为目标,则不必这样做。 Logging 库不会强迫您这样做 好的。但不幸的是,这并不能回答我的问题 @Julian 问题是什么,您希望答案是什么样的?即使您的依赖项之一将其包含在其目标中,您也没有必须以 .NET Core 3 为目标。如果您不想要 .NET Core 3 中的任何内容,则不需要 定位它【参考方案2】:

当有人安装包时,NuGet 会使用 TFM 中与项目的 TFM 最匹配的资产。它也对传递依赖项执行此操作。

例如 - 如果项目目标 netcore30 和包 A 在 lib/netcore30 和 lib/netstandard20 下有资产,则 nuget 将选择 lib/netcore30。假设包 A 依赖于 B,包 B 有 netstandard20、net472 的资产,nuget 将选择 netstandard20。

底线是,nuget 将为图中的每个包选择最佳匹配资产。因此,作为库维护者,您无需添加两个 TFM 即可支持 netcore30。您可以定位 netstandard21,这意味着基于此文档 https://docs.microsoft.com/en-us/dotnet/standard/net-standard

支持 netcore30

【讨论】:

不幸的是,这无法回答为什么 Microsoft.Extensions.Logging 以 netstandard2.0 + netcore3.0 为目标以及依赖库应该做什么。 @Julian 一个依赖库没有支持.NET Core 3,如果它不想的话。使用 Microsoft.Extensions.Logging 在 .NET Core 2.1 或 .NET Framework 4.8 中构建应用程序的人每次升级包时都会获得最新的 NuGet 包,而无需切换到 .NET Core 3 恐怕这不能回答我的问题。【参考方案3】:

作为依赖于的库维护者 Microsoft.Extensions.Logging,试图支持 .NET Core 3: 我是否也应该以 .NET Core 3 为目标 - 还是只是 .NET Standard 2.0 好 如果我不需要 .NET Core 3 的特定内容就足够了吗?

只要您的所有依赖项都以 .NET Standard 2.0 为目标,包括 Microsoft.Extensions.Logging,在您的库中定位 .NET Standard 2.0 就足够了。

作为Panagiotis Kanavos said,将 .NET Core 3.0 定位为库的使用者可能会带来好处,因此,如果是这种情况并且不会花费太多,那么请务必将 .NET Core 3.0 定位到.NET Standard 2.0 的补充。

作为karann said,nuget 将始终为图中的每个包选择最佳匹配资产。即

应用 A 使用您的库并以 .NET Core 3.0 为目标。您的库仅面向 .NET Standard 2.0。 NuGet 将使用它,这很好。 应用 A 使用您的库并以 .NET Core 3.0 为目标。您的库同时面向 .NET Standard 2.0 和 .NET Core 3.0。 NuGet 将选择 .NET Core 3.0

【讨论】:

有什么理由定位.NET Core 3.0而不是.NET Standard 2.1

以上是关于库是不是应该明确针对 .NET Core 3?的主要内容,如果未能解决你的问题,请参考以下文章

使用ASP.NET Core 3.x 构建 RESTful API P11 P12 ActionResult of T 以及 AutoMapper.md

插件项目必须是.NET 3.5 其余代码库是.NET 4.0 怎么解决?

.NET Standard / Core 中的 .vspscc 文件

.Net Core下一次针对dpz2.Json和Newtonsoft.Json解析库的简单测试

存储库是单例的还是静态的还是都不是?

ASP.NET Core 3.1 Razor 页面路由不明确匹配异常