Які наслідки застосування бібліотеки 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.3на цей frameworksрозділ і мав явну залежність від System.Runtime.Numerics, наприклад, версії 4.0.1. Створений мною пакунок перерахує саме цю залежність.

В чудовому новому світі csproj основі Dotnet інструментів (я використовую v1.0.1 з інструментів командного рядка) є більш мається на увазі посилання метапакета пакета для NETStandard.Library 1.6.1при орієнтації netstandard1.3. Це означає, що мій файл проекту дійсно малий, тому що він не потребує явної залежності:

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

... але створений пакунок нугів має залежність від 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!автономної програми зменшується до <10 МБ.
ABarney

@ABarney 10 Мб все ще занадто сильно порівняно з розміром < 20 КБ класичного проекту .NET Framework C # привіт.
Дай

Відповіді:


76

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

Рухаючись вперед, ми спростимо це:

  1. .NET Standard - це атомний будівельний блок . Іншими словами, новим платформам заборонено підмножити .NET Standard - вони повинні реалізувати все це.

  2. Ми відходимо від використання пакетів для опису наших платформ , включаючи .NET Standard.

Це означає, що вам більше не доведеться посилатися на будь-які пакети NuGet для .NET Standard. Ви виразили свою залежність за допомогою папки lib, саме так вона працювала для всіх інших платформ .NET, зокрема .NET Framework.

Однак зараз наш інструмент все ще буде записаний у посиланні на NETStandard.Library. У цьому немає ніякої шкоди, вона просто стане зайвою, рухаючись вперед.

Я оновлю FAQ на репортажі .NET Standard, щоб включити це питання.

Оновлення : це питання зараз є частиною поширених запитань .


9
Спасибі - це має багато сенсу. Я думаю, що я частково розгубився, тому що в світі project.json мені довелося додавати залежності, навіть коли пакети логічно входили в рамки, на які я орієнтувався (наприклад, System.Runtime.Numerics для netstandard1.3) - тому я подумав, що NETStandard.Library був дійсно втягуючи їх у залежність.
Джон Скіт

2
Бампер. Ідея посилатися на пакунки мені сподобалась, бо здавалося, що я можу посилатись лише на те, що хотів, а не на всю кухонну раковину. Можливо, я не думаю про це правильно?
Нейт Барбеттіні

3
Ви не обов'язково думаєте про це неправильно, але питання полягає в тому, чому вам все одно. Важливо зрозуміти, що платформа не є нескінченною для компонування. Якщо ви працюєте в середовищі спільного використання (.NET Framework, Mono, .NET Core), всі ці біти все одно присутні. Якщо ви створили автономний додаток (Xamarin, Mono / .NET Core з лінкером), ми можемо автоматично обрізати, виходячи з вашого фактичного використання. Так чи інакше, ви нічого не втрачаєте, не посилаючись на менші блоки.
Іммо Ландверт

3
А як із тим, щоб компілятор виконував такі правила, як перешкоджати розробнику робити запит http у проекті бізнес-логіки, не дозволяючи цьому пакету - марно витрачати зусилля?
Девід Ферретті

Не обов'язково, але як ви їх застосовуєте, тобто що не дозволяє розробнику додавати посилання? Я б написав аналізатор, який вводиться під час збирання для виконання правил шару та викликає помилки на машині збірки.
Іммо Ландверт

19

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

Я ніколи не отримував абсолютно прямої прямої відповіді на те, чому це сталося, тому дозвольте мені зробити декілька освічених здогадок.

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

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

Статичний аналіз може бути використаний під час публікації для обмеження відправлених DLL-файлів. Це те, що вони роблять сьогодні, коли роблять компіляцію для UWP (хоча і з деякими застереженнями). Сьогодні вони цього не роблять для .NET Core, але я вважаю, що вони розглядали оптимізацію (а також підтримують нативний код).

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


6
Я погоджуюсь, що це безумовно перемагає мету, коли існує більше ніж одна залежність, якщо будь-яка з них приводить NETStandard.Library. Звичайно, це дещо самореалізується ... якщо я залежу від NETStandard.LibraryNoda Time, це означає, що будь-яка інша бібліотека, побудована на вершині Noda Time, не має підстав для обрізання залежностей тощо. Наразі вибагливо бути вибірковою (Noda Time is Повертаючись до 2.0), тоді трохи пізніше розслабтеся після того, як будуть встановлені конвенції - перехід від селективного до ліб-коду буде безперебійною зміною, я припускаю, але зворотне не відповідає дійсності.
Джон Скіт

8

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


Якщо ви виконаєте dotnet publishпевний час виконання, він приведе всі залежності, включаючи dotnet.exe (або його еквівалент Linux / OS X). Це має бути повністю автономним розгортанням у той момент. Ознайомтесь з результатами тестового проекту для одиниць: gist.github.com/bradwilson/6cc5a8fdfa18230aa6c99b851fb85c01
Бред Вілсон

4
Я думаю, що останній абзац - це саме питання ... і якщо це не було проблемою, то навіщо нам взагалі потрібні різні версії netstandard1.x? Якщо на кожній платформі є все в netstandard1.6, чому б навіть мати netstandard1.0 як концепцію? Це для мене заплутана частина.
Джон Скіт

1
І список платформ, які підтримують .NET Standard, не включає БУДЬ-яку з багатьох платформ Unity.
Citizenmatt

1
(Ваша терпіння дуже цінується, btw. Я дуже сподіваюся, що це все матиме сенс, і що це допоможе багатьом, багатьом розробникам ...)
Джон Скіт

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.