将依赖项添加到 .NET 库的主要方法是引用 NuGet 包。 NuGet 包引用允许快速重用和利用已编写的功能,但它们是 .NET 开发人员的常见摩擦来源。 正确管理依赖项对于防止其他 .NET 库的更改对你的 .NET 库造成影响,以及使你的 .NET 库不会影响其他库,都是非常重要的。
菱形依赖关系
.NET 项目在其依赖项树中具有多个版本的包很常见。 例如,应用依赖于两个 NuGet 包,每个包都依赖于同一包的不同版本。 菱形依赖项现在存在于应用的依赖项关系图中。
在构建时,NuGet 会分析项目依赖的所有包,包括依赖项的依赖项。 检测到包的多个版本后,将评估规则以选取一个。 统一包是必需的,因为在同一应用程序中并行运行程序集的版本在 .NET 中存在问题。
大多数菱形依赖关系很容易解决;但是,在某些情况下,它们可能会引发问题:
- 存在冲突的 NuGet 包引用会导致在包还原期间无法解析版本。
- 版本之间的中断性变更 会导致运行时出现 bug 和异常。
- 包程序集具有强名称,程序集版本会发生更改,并且在 .NET Framework 上运行应用。 程序集绑定重定向是必需的。
无法确定哪些包将与你自己的包一起使用。 降低菱形依赖关系破坏库的可能性的一个好方法是将依赖的包的数量降至最低。
✔️ 请查看 .NET 库,了解不必要的依赖项。
NuGet 依赖项版本范围
包引用指定它允许的有效包的范围。 通常,项目文件中的包引用版本是最低版本,并且没有最大值。
<!-- Accepts any version 1.0 and above. -->
<PackageReference Include="ExamplePackage" Version="1.0" />
NuGet 在解析依赖项时使用的规则 很复杂,但 默认情况下 ,NuGet 会查找最低适用的版本。 NuGet 首选最低适用的版本,而不是使用可用的最高版本,因为最低版本具有最低兼容性问题。
由于 NuGet 适用的版本规则最低,因此无需在包引用上放置较高版本或确切范围,以避免获取最新版本。 NuGet 已尝试查找最低、最兼容的版本。
<!-- 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 失败。 例如,一个库只接受 1.0,而另一个库需要 2.0 或更高版本。 虽然版本 2.0 中可能引入了重大更改,但严格的或上限版本依赖项绝对会出现错误。
❌ 不要使用没有最低版本的 NuGet 包引用。
❌ 请避免使用需要确切版本的 NuGet 包引用。
❌ 避免引用带有版本上限的 NuGet 包。
有关详细信息,请参阅 包版本控制。
NuGet 共享源包
减少外部 NuGet 包依赖项的一种方法是引用共享源包。 共享源包中包含在项目中被引用的 源代码文件 。 由于你只是包括使用项目其余部分编译的源代码文件,因此没有外部依赖项和冲突的可能性。
共享源包非常适合包括少量功能。 例如,可以引用用于进行 HTTP 调用的帮助程序方法的共享源包。
<PackageReference Include="Microsoft.Extensions.Buffers.Testing.Sources" PrivateAssets="All" Version="1.0" />
共享源包存在一些限制。 它们只能被 PackageReference
引用,因此排除了较旧的 packages.config
项目。 此外,共享源包只能由具有相同语言的项目使用。 由于这些限制,共享源包最适合用于在开源项目中共享功能。
✔️ 请考虑引用共享源包以获取小型内部功能片段。
✔️ 如果包提供较小的内部功能片段,请考虑将包作为共享源包。
✔️ 请务必使用 PrivateAssets="All"
引用共享源包。
此设置告知 NuGet 包仅在开发时使用,不应公开为公共依赖项。
❌ 公共 API 中没有共享的源包类型。
共享源类型编译为引用程序集,不能跨程序集边界交换。 例如,一个项目中的共享源
IRepository
类型是另一个项目中同一共享源IRepository
的单独类型。 共享源包中的类型应具有internal
可见性。
❌ 请勿将共享源包发布到 NuGet.org。
共享源代码包包含源代码,只能由具有相同语言类型的项目使用。 例如,F# 应用程序无法使用 C# 共享源包。
将共享源包发布到 本地源或 MyGet ,以在项目中内部使用它们。