item-management
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMSBuild Item Management Patterns
MSBuild 项组管理模式
Canonical patterns for working with item groups, from .
Microsoft.Common.CurrentVersion.targets来自的项组操作标准模式。
Microsoft.Common.CurrentVersion.targetsInclude / Remove / Update — Three Operations
Include / Remove / Update — 三种操作
| Operation | Purpose | When to use |
|---|---|---|
| Add new items to the group | Creating items with identity + metadata |
| Remove items matching a pattern | Excluding files or clearing a group |
| Modify metadata on existing items | Adding/changing metadata without re-adding |
| 操作 | 用途 | 使用场景 |
|---|---|---|
| 向组中添加新项 | 创建带有标识+元数据的项 |
| 删除匹配模式的项 | 排除文件或清空组 |
| 修改现有项的元数据 | 添加/更改元数据而无需重新添加项 |
Include — Add Items
Include — 添加项
xml
<ItemGroup>
<Compile Include="Generated\*.cs">
<AutoGen>true</AutoGen>
</Compile>
</ItemGroup>xml
<ItemGroup>
<Compile Include="Generated\*.cs">
<AutoGen>true</AutoGen>
</Compile>
</ItemGroup>Remove — Subtract Items
Remove — 删除项
xml
<ItemGroup>
<!-- Remove specific items -->
<Reference Remove="$(AdditionalExplicitAssemblyReferences)" />
<!-- Set subtraction: prior minus current -->
<_CleanOrphanFileWrites Include="@(_CleanPriorFileWrites)"
Exclude="@(_CleanCurrentFileWrites)" />
<!-- Clear an entire group -->
<_Temporary Remove="@(_Temporary)" />
</ItemGroup>xml
<ItemGroup>
<!-- 删除特定项 -->
<Reference Remove="$(AdditionalExplicitAssemblyReferences)" />
<!-- 集合减法:原有项减去当前项 -->
<_CleanOrphanFileWrites Include="@(_CleanPriorFileWrites)"
Exclude="@(_CleanCurrentFileWrites)" />
<!-- 清空整个组 -->
<_Temporary Remove="@(_Temporary)" />
</ItemGroup>Update — Modify Existing Items
Update — 修改现有项
xml
<ItemGroup>
<EmbeddedResource Update="@(EmbeddedResource)"
Condition="'%(NuGetPackageId)' == 'Microsoft.CodeAnalysis.Collections'">
<GenerateSource>true</GenerateSource>
<ClassName>Microsoft.CodeAnalysis.Collections.SR</ClassName>
</EmbeddedResource>
</ItemGroup>Updatexml
<ItemGroup>
<EmbeddedResource Update="@(EmbeddedResource)"
Condition="'%(NuGetPackageId)' == 'Microsoft.CodeAnalysis.Collections'">
<GenerateSource>true</GenerateSource>
<ClassName>Microsoft.CodeAnalysis.Collections.SR</ClassName>
</EmbeddedResource>
</ItemGroup>UpdateItem Batching — %(Metadata)
项批处理 — %(Metadata)
When appears in target attributes or task parameters, MSBuild batches execution per unique metadata value.
%(Metadata)当出现在目标属性或任务参数中时,MSBuild会按唯一元数据值分批执行。
%(Metadata)Target-level batching (Outputs)
目标级批处理(Outputs)
xml
<Target Name="GenerateSatelliteAssemblies"
Inputs="$(MSBuildAllProjects);@(_SatelliteAssemblyResourceInputs)"
Outputs="$(IntermediateOutputPath)%(Culture)\$(TargetName).resources.dll">
<!-- Runs once per unique Culture value -->
</Target>xml
<Target Name="GenerateSatelliteAssemblies"
Inputs="$(MSBuildAllProjects);@(_SatelliteAssemblyResourceInputs)"
Outputs="$(IntermediateOutputPath)%(Culture)\$(TargetName).resources.dll">
<!-- 每个唯一Culture值执行一次 -->
</Target>Task-level batching
任务级批处理
xml
<Copy SourceFiles="@(_SourceItems)"
DestinationFiles="@(_SourceItems->'$(OutDir)%(TargetPath)')">
</Copy>xml
<Copy SourceFiles="@(_SourceItems)"
DestinationFiles="@(_SourceItems->'$(OutDir)%(TargetPath)')">
</Copy>Per-item filtering with Condition
使用Condition进行逐项过滤
xml
<ItemGroup>
<_ResxOutput Include="@(EmbeddedResource->'%(OutputResource)')"
Condition="'%(EmbeddedResource.WithCulture)' == 'false'" />
</ItemGroup>xml
<ItemGroup>
<_ResxOutput Include="@(EmbeddedResource->'%(OutputResource)')"
Condition="'%(EmbeddedResource.WithCulture)' == 'false'" />
</ItemGroup>Batching rules
批处理规则
- in
%(Metadata)orCondition→ target batches per unique value.Outputs - in task parameters → task batches per unique value.
%(Metadata) - Do not mix from different item groups in the same expression — this causes a cross-product (see Common Pitfalls).
%()
- 在
%(Metadata)或Condition中 → 目标按唯一值分批执行。Outputs - 在任务参数中 → 任务按唯一值分批执行。
%(Metadata) - 不要在同一表达式中混合来自不同项组的——这会导致交叉产品批处理(请参见常见问题)。
%()
Item Transforms — @(Item->'expression')
项转换 — @(Item->'expression')
Transforms create new item lists by applying an expression to each item:
xml
<!-- Transform file paths to destinations -->
<Copy SourceFiles="@(IntermediateAssembly)"
DestinationFiles="@(IntermediateAssembly->'$(OutDir)%(Filename)%(Extension)')"/>
<!-- Transform with separator for display -->
<Message Text="Files: @(Compile->'%(Filename)', ', ')" />转换通过对每个项应用表达式来创建新的项列表:
xml
<!-- 将文件路径转换为目标路径 -->
<Copy SourceFiles="@(IntermediateAssembly)"
DestinationFiles="@(IntermediateAssembly->'$(OutDir)%(Filename)%(Extension)')"/>
<!-- 使用分隔符转换用于显示 -->
<Message Text="Files: @(Compile->'%(Filename)', ', ')" />Exclude Pattern — Set Subtraction on Include
排除模式 — Include上的集合减法
xml
<ItemGroup>
<Compile Include="**\*.cs" Exclude="Generated\**;Tests\**" />
</ItemGroup>ExcludeIncludeUpdateRemovexml
<ItemGroup>
<Compile Include="**\*.cs" Exclude="Generated\**;Tests\**" />
</ItemGroup>ExcludeIncludeUpdateRemoveConditional Item Inclusion
条件性项包含
xml
<!-- Condition on ItemGroup — all or nothing -->
<ItemGroup Condition="'$(NetCoreBuild)' == 'true'">
<PackageReference Include="System.IO.Pipelines" />
</ItemGroup>
<!-- Condition on individual items -->
<ItemGroup>
<PackageReference Include="System.IO.Pipelines"
Condition="'$(NetCoreBuild)' == 'true'" />
</ItemGroup>xml
<!-- 对ItemGroup设置条件 — 全包含或全不包含 -->
<ItemGroup Condition="'$(NetCoreBuild)' == 'true'">
<PackageReference Include="System.IO.Pipelines" />
</ItemGroup>
<!-- 对单个项设置条件 -->
<ItemGroup>
<PackageReference Include="System.IO.Pipelines"
Condition="'$(NetCoreBuild)' == 'true'" />
</ItemGroup>PrivateAssets on Tool/Analyzer Packages
工具/分析器包的PrivateAssets
xml
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" PrivateAssets="all" />
</ItemGroup>xml
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" PrivateAssets="all" />
</ItemGroup>Common Pitfalls
常见问题
Cross-product batching
交叉产品批处理
Referencing from two different item groups creates O(N×M) executions:
%(Metadata)xml
<!-- BAD: Cross-product of @(Source) × @(Config) -->
<Exec Command="process %(Source.Identity) with %(Config.Identity)" />
<!-- GOOD: Reference one group via batching, the other via property -->
<Exec Command="process %(Source.Identity) with $(ConfigFile)" />引用来自两个不同项组的会产生O(N×M)次执行:
%(Metadata)xml
<!-- 错误:@(Source) × @(Config) 的交叉产品 -->
<Exec Command="process %(Source.Identity) with %(Config.Identity)" />
<!-- 正确:通过批处理引用一个组,通过属性引用另一个组 -->
<Exec Command="process %(Source.Identity) with $(ConfigFile)" />Generated files in source tree
源目录中的生成文件
Write to (obj/), not the source directory. Source-tree generation pollutes version control and can cause duplicate compilation via globs.
$(IntermediateOutputPath)写入(obj/),而不是源目录。源目录生成会污染版本控制,并可能通过通配符导致重复编译。
$(IntermediateOutputPath)Missing FileWrites
缺失FileWrites
Every file created during a target must be added to for support.
@(FileWrites)dotnet clean目标期间创建的每个文件都必须添加到中,以支持。
@(FileWrites)dotnet clean