为何传递性分析器/源代码生成器默认会传递,与文档描述不符?
NuGet官方文档指出,<PackageReference>的PrivateAssets默认值为contentfiles;analyzers;build,该属性用于指定不传递给消费项目的资产。按此逻辑,默认情况下:
- 项目A引用包B
- 包B引用包含分析器/源代码生成器的包C
那么C的分析器/源代码生成器不应传递给A,但实际情况并非如此。
最小复现步骤
- 克隆示例项目并构建:
git clone https://github.com/aradalvand/nuget-transitive-analyzer-test dotnet build
ThePackage的.nuspec内容
<?xml version="1.0" encoding="utf-8"?> <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd"> <metadata> <id>ThePackage</id> <version>1.0.0</version> <authors>ThePackage</authors> <description>Package Description</description> <repository type="git" /> <dependencies> <group targetFramework="net8.0"> <dependency id="Riok.Mapperly" version="3.6.0" exclude="Build,Analyzers" /> </group> </dependencies> </metadata> </package>
注意其中设置了exclude="Build,Analyzers",但构建ConsumingThePackage项目时,Riok.Mapperly的源代码生成器仍会执行,与预期不符。
核心原因1:PrivateAssets默认不包含buildTransitive
源代码生成器(如Riok.Mapperly)通常会打包在NuGet包的buildTransitive目录下,而NuGet的PrivateAssets默认值contentfiles;analyzers;build不包含buildTransitive。这意味着即使包B引用包C时使用默认的PrivateAssets设置,buildTransitive类型的资产(源代码生成器)仍会被传递到下游的项目A。
核心原因2:nuspec中的exclude属性作用范围有限
你在nuspec的<dependency>中设置的exclude="Build,Analyzers",仅作用于安装当前包(ThePackage)的项目,即该项目在安装ThePackage时不会获取Riok.Mapperly的Build和Analyzers资产,但这并不会阻止这些资产通过依赖传递到更下游的项目(如ConsumingThePackage)。这个属性是控制当前包安装时的资产排除,而非依赖传递的阻断。
解决方案
要彻底阻止源代码生成器传递到下游项目,需要在包B(ThePackage)的项目文件(.csproj)中,对Riok.Mapperly的<PackageReference>设置正确的PrivateAssets,包含buildTransitive:
<PackageReference Include="Riok.Mapperly" Version="3.6.0"> <PrivateAssets>contentfiles;analyzers;build;buildTransitive</PrivateAssets> </PackageReference>
或者更简洁地使用all(但会排除所有资产传递,需根据实际需求调整):
<PackageReference Include="Riok.Mapperly" Version="3.6.0"> <PrivateAssets>all</PrivateAssets> </PackageReference>
这样设置后,当ThePackage被打包并被ConsumingThePackage引用时,Riok.Mapperly的源代码生成器就不会被传递到ConsumingThePackage中,符合预期行为。
内容的提问来源于stack exchange,提问作者Arad

