web-dev-qa-db-fra.com

Quelles sont les implications pour les applications d’une bibliothèque netstandard en fonction d’un méta-paquet?

Supposons que je dispose d'une bibliothèque de classes pour laquelle je veux cibler netstandard1.3, mais que j'utilise également BigInteger. Voici un exemple trivial - le seul fichier source est 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);            
    }
}

Retour dans le monde de project.json, Je ciblerais netstandard1.3 dans la section frameworks et ont une dépendance explicite sur System.Runtime.Numerics, par exemple. version 4.0.1. Le paquet de nugets que je crée ne listera que cette dépendance.

Dans le nouveau monde des outils de dotnet basés sur csproj (j'utilise v1.0.1 des outils de ligne de commande), il existe un référence de package de métapaquet implicite à NETStandard.Library 1.6.1 lorsque vous ciblez netstandard1.3. Cela signifie que mon fichier de projet est vraiment petit, car il n'a pas besoin de la dépendance explicite:

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

... mais le paquet nuget produit a une dépendance sur NETStandard.Library, ce qui suggère que pour utiliser ma petite bibliothèque, vous avez besoin de tout .

Il s'avère que je peux désactiver cette fonctionnalité en utilisant DisableImplicitFrameworkReferences, puis ajouter à nouveau manuellement la dépendance:

<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>

Maintenant, mon paquet NuGet dit exactement de quoi cela dépend. Intuitivement, cela ressemble à un paquet "plus maigre".

Alors, quelle est la différence exacte pour un consommateur de ma bibliothèque? Si quelqu'un essaie de l'utiliser dans une application UWP, la deuxième forme de dépendance "ajustée" signifie-t-elle que l'application résultante sera plus petite?

En ne documentant pas clairement DisableImplicitFrameworkReferences (pour autant que je sache, j'ai lu à ce sujet dans un numéro ) et en faisant de la dépendance implicite la valeur par défaut lors de la création d'un projet, Microsoft are encourageant les utilisateurs à ne dépendre que du méta-paquet - mais comment puis-je être sûr que cela ne présente pas d'inconvénient lorsque je produis un paquet de bibliothèque de classes?

97
Jon Skeet

Dans le passé, nous avions recommandé aux développeurs de ne pas faire référence au méta-paquet (NETStandard.Library) des paquets NuGet mais référence à la place des paquets individuels, comme System.Runtime et System.Collections. La raison en était que nous avons considéré le méta-paquet comme un raccourci pour un ensemble de paquets qui étaient les blocs de construction atomiques de la plate-forme .NET. L'hypothèse était la suivante: nous pourrions créer une autre plate-forme .NET qui ne prend en charge que certains de ces blocs atomiques, mais pas tous. Par conséquent, moins vous référencez de paquets, plus vous serez portable. Il y avait également des préoccupations concernant la façon dont notre outillage traite les graphiques de gros paquets.

À l'avenir, nous simplifierons ceci:

  1. . NET Standard est un bloc de construction atomique . En d'autres termes, les nouvelles plateformes ne sont pas autorisées à créer un sous-ensemble .NET Standard. Elles doivent tout mettre en œuvre.

  2. Nous n'utilisons plus de packages pour décrire nos plateformes , y compris .NET Standard.

Cela signifie que vous ne devrez plus faire référence à aucun paquet NuGet pour .NET Standard. Vous avez exprimé votre dépendance vis-à-vis du dossier lib, qui est exactement comme cela a fonctionné pour toutes les autres plates-formes .NET, en particulier .NET Framework.

Cependant, pour le moment, nos outils continueront de graver dans la référence à NETStandard.Library. Il n'y a pas de mal à cela non plus, cela deviendra simplement redondant à l'avenir.

Je mettrai à jour le FAQ sur le référentiel .NET Standard pour inclure cette question.

Mise à jour : Cette question est maintenant partie de la FAQ .

75
Immo Landwerth

L’équipe recommandait de déterminer quel était le paquet le plus fin. Ils ne le font plus et recommandent aux utilisateurs de simplement importer NETStandard.Library (dans le cas d'un projet de style SDK, cette opération sera effectuée automatiquement pour vous).

Je n'ai jamais eu une réponse tout à fait simple quant à la raison, alors permettez-moi de faire des suppositions éclairées.

La raison principale en est probablement que cela leur permet de masquer les différences entre les versions des bibliothèques dépendantes que vous auriez sinon dû suivre vous-même lorsque vous modifiez les infrastructures cible. C'est aussi un système beaucoup plus convivial avec les fichiers de projet basés sur le SDK, car vous n'avez franchement pas besoin de références pour obtenir une bonne partie de la plate-forme (comme vous le faisiez avec les références par défaut dans Desktop-land, en particulier mscorlib ).

En insérant la méta-définition de ce que signifie être une bibliothèque netstandard ou une application netcoreapp dans le package NuGet approprié, ils ne doivent pas intégrer de connaissances spéciales à la définition de ces choses comme Visual Studio (ou dotnet new) les voit.

L'analyse statique peut être utilisée lors de la publication pour limiter les DLL livrées, ce qui est le cas aujourd'hui lors de la compilation native pour UWP (à quelques réserves près). Ils ne le font pas aujourd'hui pour .NET Core, mais je présume que c'est une optimisation qu'ils ont envisagée (en plus de prendre en charge le code natif).

Rien ne vous empêche d'être très sélectif, si vous le souhaitez. Je crois que vous constaterez que vous êtes presque le seul à le faire, ce qui va également à l’encontre du but recherché (puisqu’on présumera que tout le monde apporte NETStandard.Library ou Microsoft.NETCore.App).

18
Brad Wilson

Vous ne devriez pas avoir besoin de désactiver la référence implicite. Toutes les plates-formes sur lesquelles la bibliothèque pourra s'exécuter auront déjà les assemblys nécessaires à la dépendance NETStandard.Library.

La bibliothèque standard .NET est une spécification, un ensemble d'assemblys de référence que vous compilez, qui fournit un ensemble d'API dont l'existence est garantie sur un ensemble connu de plates-formes et de versions de plates-formes, telles que .NET Core ou .NET Framework. . Ce n'est pas une implémentation de ces assemblys, juste assez de la forme de l'API pour permettre au compilateur de générer votre code avec succès.

L'implémentation de ces API est fournie par une plate-forme cible, telle que .NET Core, Mono ou .NET Framework. Ils sont livrés avec la plate-forme, car ils constituent une partie essentielle de la plate-forme. Il n'est donc pas nécessaire de spécifier un ensemble de dépendances plus petit: tout y est déjà, vous ne pourrez rien y changer.

Le package NETStandard.Library Fournit ces assemblys de référence. Un point de confusion est le numéro de version - le package est la version 1.6.1, mais cela ne signifie pas ".NET Standard 1.6". C'est juste la version du paquet.

La version de .NET Standard que vous ciblez provient du framework cible que vous spécifiez dans votre projet.

Si vous créez une bibliothèque et souhaitez qu'elle s'exécute sur .NET Standard 1.3, vous devez référencer le package NETStandard.Library, Actuellement à la version 1.6.1. Mais plus important encore, votre fichier de projet ciblerait netstandard1.3.

Le paquet NETStandard.Library Vous donnera un ensemble différent d’ensembles de référence en fonction du nom de votre framework cible (pour simplifier, par souci de brièveté, mais pensez à lib\netstandard1.0, lib\netstandard1.1 Et groupes de dépendance ). Donc, si votre projet cible netstandard1.3, Vous obtiendrez les assemblys de référence 1.3. Si vous ciblez netstandard1.6, Vous obtiendrez les assemblys de référence 1.6.

Si vous créez une application, vous ne pouvez pas cibler le standard .NET. Cela n'a aucun sens - vous ne pouvez pas utiliser une spécification. Au lieu de cela, vous ciblez des plates-formes concrètes, telles que net452 Ou netcoreapp1.1. NuGet connaît le mappage entre ces plateformes et les monikers du cadre cible netstandard. Il sait donc quels dossiers lib\netstandardX.X Sont compatibles avec votre plate-forme cible. Il sait également que les dépendances de NETStandard.Library Sont satisfaites par la plate-forme cible et n'entraîneront donc aucun autre assemblage.

De même, lors de la création d'une application .NET Core autonome, les assemblys d'implémentation .NET Standard sont copiés avec votre application. La référence à NETStandard.Library N'apporte aucune autre nouvelle application.

Notez que dotnet publish Créera une application autonome , mais ne coupera pas pour le moment, et publiera tous les assemblys. Ce sera manipulé automatiquement par outillage , donc encore une fois, le fait de couper les dépendances dans votre bibliothèque ne va pas aider ici.

Le seul endroit où je peux imaginer où pourrait aider à supprimer la référence NETStandard.Library Est si vous ciblez une plate-forme qui ne prend pas en charge .NET Standard et vous pouvez trouver un package à partir de .NET Standard où toutes les dépendances transitives peuvent s'exécuter sur votre plate-forme cible. Je soupçonne qu’il n’ya pas beaucoup de colis qui conviendraient à ce projet de loi.

8
citizenmatt