Каковы прикладные значения библиотеки netstandard в зависимости от метапакета?

Предположим, что у меня есть библиотека классов, для которой я хочу настроить 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, который я создам, будет отображаться только эта зависимость.

В смелом новом мире инструментария dotnet, основанного на csproj (я использую v1.0.1 инструментов командной строки) там неявная ссылка пакета метапакетов до NETStandard.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 точно определяет, от чего это зависит. Интуитивно это похоже на "более компактный" пакет.

Итак, какая именно разница для потребителя моей библиотеки? Если кто-то пытается использовать его в приложении UWP, вторая, "обрезанная" форма зависимостей означает, что результирующее приложение будет меньше?

Не документируя DisableImplicitFrameworkReferences ясно (насколько я видел, я читал об этом в проблеме) и неявная зависимость по умолчанию при создании проекта, Microsoft поощряет пользователей просто зависеть от метапакета, но как я могу быть уверен, что у меня нет недостатков, когда я создаю пакет библиотеки классов?

Ответ 1

В прошлом мы дали разработчикам рекомендацию не ссылаться на мета пакета (NETStandard.Library) из пакетов NuGet, но вместо этого ссылка отдельные пакеты, например System.Runtime и System.Collections. Обоснование заключалось в том, что мы думали о мета-пакете как сокращении для кучи пакеты, которые были фактическими атомными строительными блоками платформы .NET. предположение было: мы могли бы создать еще одну платформу .NET, которая только поддерживает некоторые из этих атомных блоков, но не все из них. Следовательно, чем меньше пакетов вы ссылаетесь, тем более портативными вы будете. Были также опасения относительно того, как наши инструменты имеют дело с большими графами пакетов.

Двигаясь вперед, мы упростим это:

  • Стандарт .NET - это атомный строительный блок. Другими словами, новые платформы не разрешено подмножество .NET Standard - им нужно реализовать все это.

  • Мы отказываемся от использования пакетов для описания наших платформ, включая .NET Standard.

Это означает, что вам не нужно ссылаться на любые пакеты NuGet для .NET Standard больше. Вы указали свою зависимость с папкой lib, что точно так же он работал для всех других платформ .NET, в частности .NET Framework.

Однако, сейчас наши инструменты все еще будут записываться в ссылке на NETStandard.Library. В этом тоже нет вреда, он просто станет избыточное перемещение вперед.

Я обновлю FAQ в реестре .NET Standard, чтобы включить этот вопрос.

Обновление: этот вопрос теперь часть часто задаваемых вопросов.

Ответ 2

Команда использовала рекомендации, чтобы выяснить, какой самый тонкий набор пакетов. Они больше не делают этого и рекомендуют, чтобы люди просто ввели NETStandard.Library(в случае проекта в стиле SDK это будет сделано автоматически для вас).

Я никогда не получал совершенно прямого ответа относительно того, почему это было, поэтому позвольте мне сделать некоторые обоснованные предположения.

Основная причина заключается в том, что он позволяет им скрывать различия в версиях зависимых библиотек, которые вам в противном случае требовалось бы отслеживать при изменении целевых фреймворков. Это также гораздо более удобная для пользователя система с файлами проектов на базе SDK, потому что вы откровенно не нуждаетесь ни в каких ссылках, чтобы получить приличный кусок платформы (так же, как вы использовали ссылки по умолчанию в Desktop-land, особенно mscorlib).

Нажав мета-определение того, что значит быть библиотекой netstandard, или приложение netcoreapp в соответствующий пакет NuGet, им не нужно создавать какие-либо специальные знания в определении этих вещей, как Visual Studio (или dotnet new) видит их.

Статический анализ можно было использовать во время публикации, чтобы ограничить поставляемые DLL, что они делают сегодня, когда делают встроенную компиляцию для UWP (хотя и с некоторыми предостережениями). Они не делают этого сегодня для .NET Core, но я предполагаю, что он оптимизировал их (а также поддерживает собственный код).

Там ничего не мешает вам быть очень избирательным, если вы так решите. Я считаю, что вы обнаружите, что вы почти единственный, кто делает это, что также побеждает цель (так как предполагается, что все приносят NETStandard.Library или Microsoft.NETCore.App).

Ответ 3

Вам не нужно отключать неявную ссылку. Все платформы, на которые будет работать библиотека, уже будут иметь сборки, для которых потребуется зависимость 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, на который вы нацеливаетесь, исходит из целевой структуры, указанной в вашем проекте.

Если вы создаете библиотеку и хотите, чтобы она выполнялась на .NET Standard 1.3, вы должны ссылаться на пакет NETStandard.Library, в настоящее время на версию 1.6.1. Но что более важно, ваш файл проекта будет нацелен на netstandard1.3.

Пакет NETStandard.Library предоставит вам другой набор ссылочных сборок в зависимости от вашего целевого фреймворка (я упрощаю для краткости, но думаю lib\netstandard1.0, lib\netstandard1.1 и группы зависимостей). Поэтому, если ваш проект нацелен на netstandard1.3, вы получите сборку 1.3 ссылок. Если вы нацелитесь на netstandard1.6, вы получите 1.6 ссылочные сборки.

Если вы создаете приложение, вы не можете настроить таргетинг на .NET Standard. Это не имеет смысла - вы не можете работать по спецификации. Вместо этого вы нацелитесь на конкретные платформы, такие как net452 или netcoreapp1.1. NuGet знает сопоставление между этими платформами и прокси-серверами netstandard, поэтому знает, какие папки lib\netstandardX.X совместимы с вашей целевой платформой. Он также знает, что зависимости NETStandard.Library удовлетворяются целевой платформой, поэтому не будут тянуть любые другие сборки.

Аналогично, при создании автономного приложения .NET Core сборка реализации .NET Standard копируется с вашим приложением. Ссылка на NETStandard.Library не содержит никаких других новых приложений.

Обратите внимание, что dotnet publish создаст автономное приложение, но в настоящее время оно не будет выполнять обрезку и опубликует все сборки. Это будет обработано автоматически с помощью инструментария, так что опять-таки зависимостей обрезки в вашей библиотеке здесь не поможет.

Единственное место, где я могу представить, где это может помочь удалить ссылку NETStandard.Library, - это таргетинг на платформу, которая не поддерживает стандарт .NET, и вы можете найти пакет из .NET Standard, где все транзитивных зависимостей может работать на вашей целевой платформе. Я подозреваю, что не так много пакетов, которые бы соответствовали этому счету.