メタパッケージに依存するネットスタンダードライブラリのアプリケーションへの影響は何ですか?


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.3frameworksセクション、そして上の明示的な依存関係持ってSystem.Runtime.Numerics、例えばバージョン4.0.1を。私が作成するnugetパッケージには、その依存関係のみがリストされます。

csprojベースのドットネットツールの勇敢な新しい世界(コマンドラインツールのv1.0.1を使用しています)には、を対象とする場合の暗黙的なメタパッケージパッケージ参照があります。これは、明示的な依存関係を必要としないため、プロジェクトファイルが本当に小さいことを意味します。NETStandard.Library 1.6.1netstandard1.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アプリケーションでそれを使用しようとした場合、2番目の「トリミングされた」形式の依存関係は、結果のアプリケーションが小さくなることを意味しますか?

DisableImplicitFrameworkReferences(私が見た限りでは、問題の中でそれを読みました)明確に文書化せず、プロジェクトの作成時に暗黙的な依存関係をデフォルトにすることで、Microsoftはユーザーにメタパッケージだけに依存するように勧めています-しかし、どのようにしてクラスライブラリパッケージを作成するときに、デメリットはありませんか?


3
依存関係のトリミングが行われていることに注意してください。現在、Hello World!自己完結型アプリケーションのサイズは10MB未満に縮小されています。
ABarney 2017年

@ABarney 10MBは、従来の.NET Framework C#hello-worldプロジェクトの20KB未満のサイズと比較すると、まだ大きすぎます。
Dai

回答:


76

過去にはNETStandard.Library、NuGetパッケージからメタパッケージ()を参照するのではなく、System.Runtimeおよびのような個々のパッケージを参照することを推奨していましたSystem.Collections。理論的根拠は、メタパッケージを、.NETプラットフォームの実際のアトミックなビルディングブロックである一連のパッケージの省略形と考えていたことです。想定は、これらのアトミックブロックのすべてではなく一部のみをサポートする別の.NETプラットフォームを作成する可能性があるということでした。したがって、参照するパッケージが少ないほど、移植性が高くなります。また、私たちのツールが大きなパッケージグラフをどのように扱うかについても懸念がありました。

今後は、これを簡略化します。

  1. .NET Standardはアトミックビルディングブロックです。言い換えると、新しいプラットフォームでは.NET Standardをサブセット化することはできません。すべてのプラットフォームを実装する必要があります。

  2. .NET Standardを含む、プラットフォームの記述にパッケージを使用することから離れます。

つまり、.NET StandardのNuGetパッケージを参照する必要がなくなります。libフォルダーを使用して依存関係を表現しました。これは、他のすべての.NETプラットフォーム、特に.NET Frameworkでの動作とまったく同じです。

ただし、現在のところ、ツールへの参照は引き続き使用され NETStandard.Libraryます。その点でも害はありません。前進するだけで冗長になります。

.NET StandardリポジトリのFAQを更新して、この質問を含めます。

更新:この質問はFAQの一部になりました


9
ありがとう-これは理にかなっています。project.jsonの世界では、パッケージが対象のフレームワークの論理的な一部である場合でも依存関係を追加する必要があったため(たとえば、netstandard1.3のSystem.Runtime.Numerics)、NETStandard.Libraryは依存関係としてそれらを実際に取り込みます。
Jon Skeet 2017年

2
残念。「キッチンシンク」全体ではなく、必要なものだけを参照できるように感じたので、パッケージを参照するというアイデアが気に入りました。多分私はそれについて正しく考えていませんか?
Nate Barbettini 2017年

3
あなたは必ずしもそれを間違った方法で考えているわけではありませんが、問題はなぜあなたが気にするのかです。プラットフォームは無限に構成可能ではないことを理解することが重要です。共有フレームワーク環境(.NET Framework、Mono、.NET Core)で実行する場合、これらのビットはすべて存在します。自己完結型アプリ(Xamarin、Mono / .NET Coreとリンカー)をビルドすると、実際の使用状況に基づいて自動的にトリミングできます。したがって、どちらの方法でも、小さいブロックを参照しないことで何も失うことはありません。
Immo Landwerth 2017年

3
コンパイラーに、パッケージを許可しないことによって開発者がビジネスロジックプロジェクトでhttpリクエストを作成できないようにするルールを適用することについてはどうですか?
David Ferretti、2017年

必ずしもそうとは限りませんが、どのようにしてそれを強制しますか。つまり、開発者が参照を追加できないのはなぜですか。レイヤールールを適用するためにビルド時に挿入され、ビルドマシンでエラーが発生するアナライザーを作成します。
Immo Landwerth 2017年

19

チームはかつて、最もスリムなパッケージセットを理解することを推奨していました。彼らはもはやこれを行わず、代わりにNETStandard.Libraryを持ち込むことをお勧めします(SDKスタイルのプロジェクトの場合、これは自動的に行われます)。

それがなぜであるかについて完全に簡単な答えを得たことは一度もないので、知識に基づいた推測をさせてください。

主な理由は、ターゲットフレームワークを変更するときに追跡する必要がある依存ライブラリのバージョンの違いを隠すことができるためです。また、プラットフォームのまともなチャンクを取得するために参照を必要としないので、SDKベースのプロジェクトファイルを備えた、はるかにユーザーフレンドリーなシステムです(デスクトップランドのデフォルト参照、特にmscorlibで使用していたのと同じです)。 )。

netstandardライブラリまたはnetcoreappアプリケーションとは何かのメタ定義を適切なNuGetパッケージにプッシュすることで、Visual Studio(またはdotnet new)がそれらを認識するときに、それらの定義に特別な知識を組み込む必要がなくなります。

パブリッシュ中に静的分析を使用して、出荷されたDLLを制限することができます。これは、UWPのネイティブコンパイルを実行するときに、いくつかの注意点がありますが、今日行われていることです。彼らは現在.NET Coreに対してそれを行っていませんが、私はそれが彼らが検討した最適化(およびネイティブコードのサポート)であると思います。

あなたがそう選ぶなら、あなたが非常に選択的であることを妨げるものは何もありません。私は(誰もがにもたらしていると想定されますので、また目的に反している、あなたはそれをやってほぼ唯一のだとわかります信じていますNETStandard.LibraryMicrosoft.NETCore.App)。


6
依存関係が1つ以上ある場合、それらのいずれかがもたらすと、それは目的を完全に無効にすることに同意しNETStandard.Libraryます。もちろん、それはやや自己実現的です... 野田タイム依存しNETStandard.Libraryている場合、それは野田タイムの上に構築された他のライブラリには依存関係をトリミングする理由がないことを意味します。 2.0に向かって)その後、慣例が確立されたら少し後でリラックスします-選択からlibベースへの変更は重大な変更ではないと思いますが、その逆は当てはまりません。
ジョンスキート2017年

8

暗黙的な参照を無効にする必要はありません。ライブラリが実行できるすべてのプラットフォームには、NETStandard.Library依存関係に必要なアセンブリが既に含まれています。

.NET標準ライブラリは、.NET Coreや.NET Frameworkなどのプラットフォームの既知のセットとバージョンに存在することが保証されているAPIのセットを提供する、コンパイル対象の参照アセンブリのセットである仕様です。 。これは、これらのアセンブリの実装ではなく、コンパイラーがコードを正常にビルドできるようにするためのAPIの形を十分に備えています。

これらのAPIの実装は、.NET Core、Mono、.NET Frameworkなどのターゲットプラットフォームによって提供されます。それらはプラットフォームの重要な部分であるため、プラットフォームとともに出荷されます。したがって、より小さな依存関係セットを指定する必要はありません。すべてがすでに存在しているので、それを変更することはありません。

NETStandard.Libraryパッケージには、これらの参照アセンブリを提供します。混乱の1つの点はバージョン番号です-パッケージはバージョン1.6.1ですが、これは「.NET Standard 1.6」を意味するものではありません。それはパッケージのバージョンです。

対象とする.NET標準のバージョンは、プロジェクトで指定するターゲットフレームワークから取得されます。

ライブラリを作成して.NET Standard 1.3で実行する場合は、NETStandard.Libraryパッケージを参照します。現在のバージョンは1.6.1です。しかし、より重要なのは、プロジェクトファイルがをターゲットにすることnetstandard1.3です。

このNETStandard.Libraryパッケージは、ターゲットフレームワークモニカーに応じて異なる参照アセンブリのセットを提供します(簡潔にするために単純化していますがlib\netstandard1.0lib\netstandard1.1依存グループ)。したがって、プロジェクトがをターゲットnetstandard1.3にしている場合は、1.3参照アセンブリを取得します。をターゲットnetstandard1.6にすると、1.6のリファレンスアセンブリを取得できます。

アプリケーションを作成している場合、.NET標準をターゲットにすることはできません。意味がありません-仕様で実行することはできません。代わりに、net452またはなどの具体的なプラットフォームをターゲットにしますnetcoreapp1.1。NuGetは、これらのプラットフォームとnetstandardターゲットフレームワークモニカー間のマッピングを知っているため、ターゲットプラットフォームとlib\netstandardX.X互換性のあるフォルダーを知っています。またNETStandard.Library、ターゲットプラットフォームによっての依存関係が満たされていることも認識しているため、他のアセンブリはプルインしません。

同様に、スタンドアロンの.NET Coreアプリを作成すると、.NET Standard実装アセンブリがアプリとともにコピーされます。への参照NETStandard.Libraryは、他の新しいアプリを持ち込みません。

dotnet publishスタンドアロンアプリケーションを作成しますが、それは現在、トリミングをしないではないだろう、とすべてのアセンブリを公開します。これはtoolingによって自動的処理されるので、ライブラリの依存関係を削除しても役に立ちません。

参照を削除するのに役立つ可能性があると私が想像できる唯一の場所NETStandard.Libraryは、.NET標準をサポートしていないプラットフォームをターゲットにしている場合であり、推移的な依存関係のすべてが実行できる.NET標準からパッケージを見つけることができますターゲットプラットフォームで。その法案に合うパッケージはあまりないのではないかと思います。


そうした場合dotnet publish、特定のランタイムに、それはdotnet.exe(またはそのLinuxの/ OS Xに相当)を含め、すべての依存関係にもたらすでしょう。その時点では、完全にスタンドアロンの展開になります。単体テストプロジェクトの結果を確認してください:gist.github.com/bradwilson/6cc5a8fdfa18230aa6c99b851fb85c01
Brad Wilson

4
私は最後の段落がまさに問題だと思います...そしてそれが問題でなければ、なぜnetstandard1.xの異なるバージョンが必要なのでしょうか?すべてのプラットフォームがnetstandard1.6のすべてを持っている場合は、その理由さえ持っている概念としてnetstandard1.0を?それは私にとって混乱する部分です。
ジョンスキート2017年

1
また、.NET標準をサポートするプラットフォームのリストには、多くのUnityプラットフォームのどれも含まれていません。
シチズンマット2017年

1
(あなたの忍耐は大いに感謝されます、私はこれがすべて理にかなっていて、それが多くの多くの開発者に役立つことを本当に望んでいます...)
Jon Skeet

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.