依存関係Dependencies

.NET ライブラリに依存関係を追加する主な方法は、NuGet パッケージを参照することです。The primary way of adding dependencies to a .NET library is referencing NuGet packages. NuGet パッケージ参照を使用すると、既に記述した機能をすぐに再利用して活用できますが、これは .NET 開発者にとってよくある衝突の原因となります。NuGet package references allow you to quickly reuse and leverage already written functionality, but they're a common source of friction for .NET developers. 依存関係を正しく管理することは、他の .NET ライブラリの変更によって自分の .NET ライブラリと互換性がなくなる問題、またはその逆の問題を防ぐために重要です。Correctly managing dependencies is important to prevent changes in other .NET libraries from breaking your .NET library, and vice versa!

ひし形の依存関係Diamond dependencies

.NET プロジェクトの依存関係ツリーに複数のバージョンのパッケージがあることは一般的です。It's a common situation for a .NET project to have multiple versions of a package in its dependency tree. たとえば、アプリが 2 つの NuGet パッケージに依存し、各パッケージが同じパッケージの異なるバージョンに依存しているとします。For example, an app depends on two NuGet packages, each of which depends on different versions of the same package. これで、ひし形の依存関係がアプリの依存関係グラフに存在することになります。A diamond dependency now exists in the app's dependency graph.

ひし形の依存関係Diamond dependency

ビルド時に、NuGet では、依存関係の依存関係を含め、プロジェクトが依存するすべてのパッケージが分析されます。At build time, NuGet analyzes all the packages that a project depends on, including the dependencies of dependencies. 複数バージョンのパッケージが検出されると、規則が評価され、1 つが選択されます。When multiple versions of a package are detected, rules are evaluated to pick one. 同じアプリケーション内で複数バージョンのアセンブリを並列して実行すると .NET で問題が発生するため、パッケージを統一する必要があります。Unifying packages is necessary because running side-by-side versions of an assembly in the same application is problematic in .NET.

ほとんどのひし形の依存関係は簡単に解決できますが、状況によっては問題が発生することがあります。Most diamond dependencies are easily resolved; however, they can create issues in certain circumstances:

  1. 競合する NuGet パッケージ参照があると、パッケージの復元中にバージョンが解決されません。Conflicting NuGet package references prevent a version from being resolved during package restore.
  2. バージョン間で破壊的変更があると、実行時にバグと例外が発生します。Breaking changes between the versions cause bugs and exceptions at run time.
  3. パッケージ アセンブリが厳密な名前で、アセンブリ バージョンが変わり、アプリが .NET Framework 上で実行されている場合。The package assembly is strong named, the assembly version changed, and the app is running on the .NET Framework. アセンブリのバインド リダイレクトが必要です。Assembly binding redirects are required.

自分のパッケージと共に使用されるパッケージを知ることはできません。It's not possible to know what packages will be used alongside your own. ライブラリが中断するひし形の依存関係の可能性を減らすには、依存しているパッケージの数を最小限に抑えることをお勧めします。A good way to reduce the likelihood of a diamond dependency breaking your library is to minimize the number of packages you depend on.

✔️ .NET ライブラリに不要な依存関係がないか確認してください。✔️ DO review your .NET library for unnecessary dependencies.

NuGet の依存関係バージョンの範囲NuGet dependency version ranges

パッケージ参照では、適用できる有効なパッケージの範囲を指定します。A package reference specifies the range of valid packages it allows. 通常、プロジェクト ファイルのパッケージ参照バージョンは最低バージョンであり、最高バージョンはありません。Typically, the package reference version in the project file is the minimum version and there's no maximum.

<!-- Accepts any version 1.0 and above. -->
<PackageReference Include="ExamplePackage" Version="1.0" />

依存関係を解決するときに NuGet で使用される規則は複合ですが、NuGet の既定では適用可能な最低バージョンが検索されます。The rules that NuGet uses when resolving dependencies are complex, but NuGet by default looks for the lowest applicable version. 互換性の問題が最も少ないのは最低バージョンなので、NuGet では、適用できる最高バージョンよりも適用できる最低バージョンが優先されます。NuGet prefers the lowest applicable version over using the highest available because the lowest will have the least compatibility issues.

NuGet の適用できる最低バージョン規則があるので、最新のバージョンを取得しないようにパッケージ参照に上限のバージョンまたは正確な範囲を指定する必要はありません。Because of NuGet's lowest applicable version rule, it isn't necessary to place an upper version or exact range on package references to avoid getting the latest version. NuGet は、最低の最も互換性の高いバージョンを自動的に検索しようとします。NuGet already tries to find the lowest, most compatible version for you.

<!-- Accepts 1.0 up to 1.x, but not 2.0 and higher. -->
<PackageReference Include="ExamplePackage" Version="[1.0,2.0)" />

<!-- Accepts exactly 1.0. -->
<PackageReference Include="ExamplePackage" Version="[1.0]" />

上限のバージョンを指定すると、競合がある場合に NuGet が失敗します。Upper version limits will cause NuGet to fail if there's a conflict. たとえば、あるライブラリが 1.0 のみを受け入れ、別のライブラリが 2.0 以降を必要としているとします。For example, one library accepts exactly 1.0 while another library requires 2.0 or above. バージョン 2.0 に互換性に影響する変更が組み込まれた可能性はありますが、厳密なバージョンやバージョンの上限が指定されていると、確実にエラーが発生します。While breaking changes may have been introduced in version 2.0, a strict or upper limit version dependency guarantees an error.

ひし形の依存関係の競合Diamond dependency conflict

❌ 最小バージョンを指定していない NuGet パッケージ参照を使用しないでください。❌ DO NOT have NuGet package references with no minimum version.

❌ 正確なバージョンを要求する NuGet パッケージ参照は回避してください。❌ AVOID NuGet package references that demand an exact version.

❌ バージョンの上限がある NuGet パッケージ参照を使用しないでください。❌ AVOID NuGet package references with a version upper limit.

NuGet 共有ソース パッケージNuGet shared source packages

外部 NuGet パッケージの依存関係を減らす方法の 1 つは、共有ソース パッケージを参照することです。One way to reduce external NuGet package dependencies is to reference shared source packages. 共有ソース パッケージには、参照時にプロジェクトに含まれるソース コード ファイルが含まれています。A shared source package contains source code files that are included in a project when referenced. プロジェクトの他の部分と共にコンパイルされたソース コード ファイルのみを含めているので、外部の依存関係がなく、競合が発生する可能性がありません。Because you're just including source code files that are compiled with the rest of your project, there's no external dependency and chance of conflict.

共有ソース パッケージは、小規模な機能を組み込む場合に最適です。Shared source packages are great for including small pieces of functionality. たとえば、HTTP 呼び出しを行うヘルパー メソッドの共有ソース パッケージです。For example, a shared source package of helper methods for making HTTP calls.

共有ソース パッケージShared source package

<PackageReference Include="Microsoft.Extensions.Buffers.Testing.Sources" PrivateAssets="All" Version="1.0" />

共有ソース プロジェクトShared source project

共有ソース パッケージにはいくつの制限があります。Shared source packages have some limitations. 参照できるのは PackageReference からのみなので、以前の packages.config プロジェクトは除外されます。They can only be referenced by PackageReference, so older packages.config projects are excluded. また、共有ソース パッケージは、言語の種類が同じプロジェクトからのみ使用できます。Also shared source packages are only usable by projects with the same language type. これらの制限があるため、共有ソース パッケージは、オープン ソース プロジェクト内で機能を共有する場合に最適です。Because of these limitations shared source packages are best used to share functionality within an open-source project.

✔️ 小規模な内部の機能の場合には、共有ソース パッケージを参照することを検討してください。✔️ CONSIDER referencing shared source packages for small, internal pieces of functionality.

✔️ パッケージで小規模な内部の機能を提供する場合には、それを共有ソース パッケージにすることを検討してください。✔️ CONSIDER making your package a shared source package if it provides small, internal pieces of functionality.

✔️ 共有ソース パッケージは PrivateAssets="All" を使用して参照してください。✔️ DO reference shared source packages with PrivateAssets="All".

この設定で、これが開発時にのみ使用されるパッケージであり、パブリックな依存関係として公開されないように NuGet に指示します。This setting tells NuGet the package is only to be used at development time and shouldn't be exposed as a public dependency.

❌ パブリック API に共有ソース パッケージの種類を含めないでください。❌ DO NOT have shared source package types in your public API.

共有ソースの種類は参照アセンブリにコンパイルされ、アセンブリ境界を越えて交換することはできません。Shared source types are compiled into the referencing assembly and can't be exchanged across assembly boundaries. たとえば、あるプロジェクトの共有ソースの種類 IRepository は別のプロジェクトの同じ共有ソース IRepository とは別の種類です。For example, a shared-source IRepository type in one project is a separate type from the same shared-source IRepository in another project. 共有ソース パッケージの種類には internal の可視性が必要です。Types in shared source packages should have an internal visibility.

❌ 共有ソース パッケージを NuGet.org に公開しないでください。❌ DO NOT publish shared source packages to NuGet.org.

共有ソース パッケージにはソース コードが含まれており、言語の種類が同じプロジェクトでのみ使用できます。Shared source packages contain source code and can only be used by projects with the same language type. たとえば、C# 共有ソース パッケージを F# アプリケーションで使用することはできません。For example, a C# shared source package cannot be used by an F# application.

共有ソース パッケージは、プロジェクト内で内部的に使用するように、ローカル フィードまたは MyGet に公開します。Publish shared source packages to a local feed or MyGet to consume them internally within your project.