关于 property-patterns
记录 MSBuild 属性规范模式的参考 Skill,涵盖默认值、条件、组合、路径和求值顺序,适用于维护 MSBuild 项目文件。
主要功能
- 01可覆盖的条件默认值
- 02嵌套条件属性组
- 03以分号组合属性
- 04路径规范化模式
- 05目标框架与版本保护条件
- 06求值顺序和回退指南
适用场景
- 01定义可由调用方覆盖的默认值
- 02安全追加常量或警告代码
- 03规范化项目文件中的路径
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ dotnet/ skills --skill property-patterns安装后在 Claude Code 中输入/property-patterns确认已加载。
详细介绍
MSBuild 属性模式
MSBuild 仓库中的规范属性定义和操作模式。
条件默认值——基础模式
仅当属性尚未设置时才设置,允许调用方覆盖:
<PropertyGroup>
<Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
<Platform Condition="'$(Platform)' == ''">AnyCPU</Platform>
<BuildInParallel Condition="'$(BuildInParallel)' == ''">true</BuildInParallel>
</PropertyGroup>
规则
- 两侧始终加引号:
'$(Prop)' == '' - 在
.props中:创建可覆盖的默认值。在.targets中:创建回退值。 - 不带条件的属性无法被较早导入的内容覆盖。
嵌套条件组
在共享条件下对相关属性进行分组:
<PropertyGroup Condition="$(TargetFramework.StartsWith('net4'))">
<DefineConstants>$(DefineConstants);FEATURE_APARTMENT_STATE</DefineConstants>
<DefineConstants>$(DefineConstants);FEATURE_APM</DefineConstants>
<FeatureAppDomain>true</FeatureAppDomain>
</PropertyGroup>
<PropertyGroup Condition="'$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)'))' == '.NETCoreApp'">
<NetCoreBuild>true</NetCoreBuild>
<DefineConstants>$(DefineConstants);RUNTIME_TYPE_NETCORE</DefineConstants>
</PropertyGroup>
在 PropertyGroup 上使用外层 Condition,避免在每个属性上重复相同的条件。
警告: 对于单目标项目,在项目主体求值之前,
$(TargetFramework)在.props文件中为空。请将以TargetFramework为条件的属性组放在.targets文件(或项目文件本身)中,此时该值始终可用。
组合——分号拼接
保存列表的属性使用分号。追加时始终包含现有值:
<PropertyGroup>
<DefineConstants>$(DefineConstants);MY_FEATURE</DefineConstants>
<NoWarn>$(NoWarn);NU5131;IDE0005</NoWarn>
<LibraryTargetFrameworks>$(FullFrameworkTFM);$(LatestDotNetCoreForMSBuild);netstandard2.0</LibraryTargetFrameworks>
</PropertyGroup>
路径规范化和尾随斜杠
<PropertyGroup>
<OutDir Condition="'$(OutDir)' != '' and !HasTrailingSlash('$(OutDir)')">$(OutDir)\</OutDir>
</PropertyGroup>
<PropertyGroup>
<TargetRefPath>$([MSBuild]::NormalizePath('$(TargetDir)', 'ref', '$(TargetFileName)'))</TargetRefPath>
</PropertyGroup>
<PropertyGroup>
<MSBuildProjectExtensionsPath
Condition="'$([System.IO.Path]::IsPathRooted('$(MSBuildProjectExtensionsPath)'))' == 'false'">
$([System.IO.Path]::Combine('$(MSBuildProjectDirectory)', '$(MSBuildProjectExtensionsPath)'))
</MSBuildProjectExtensionsPath>
</PropertyGroup>
首选路径函数
| 函数 | 用途 |
|---|---|
$([MSBuild]::NormalizePath(...)) | 合并并规范化(跨平台) |
$([System.IO.Path]::Combine(...)) | 合并路径片段 |
$([System.IO.Path]::IsPathRooted(...)) | 检查是否为绝对路径 |
HasTrailingSlash(...) | 检查是否有尾随斜杠 |
$([MSBuild]::GetDirectoryNameOfFileAbove(...)) | 向上遍历目录树 |
$(MSBuildThisFileDirectory) | 当前文件所在目录 |
目标框架检测辅助项
<PropertyGroup Condition="'$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)'))' == '.NETCoreApp'">
<NetCoreBuild>true</NetCoreBuild>
</PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net472'))">
<UseFrozenVersions>true</UseFrozenVersions>
</PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('windows'))">
<DefineConstants>$(DefineConstants);TEST_ISWINDOWS</DefineConstants>
</PropertyGroup>
守卫属性
标记文件已导入,以防止重复导入:
<PropertyGroup>
<MySDKPropsImported>true</MySDKPropsImported>
</PropertyGroup>
<Import Project="MySDK.props" Condition="'$(MySDKPropsImported)' != 'true'" />
按 MSBuild 版本控制功能
<PropertyGroup Condition="$([MSBuild]::AreFeaturesEnabled('17.10'))">
<UseNewBehavior>true</UseNewBehavior>
</PropertyGroup>
回退链
先通过主要来源设置,然后再回退:
<PropertyGroup>
<TlbExpPath>$([Microsoft.Build.Utilities.ToolLocationHelper]::GetPathToDotNetFrameworkSdkFile('tlbexp.exe'))</TlbExpPath>
<TlbExpPath Condition="'$(TlbExpPath)' == ''">$(_NetFxToolsDir)TlbExp.exe</TlbExpPath>
</PropertyGroup>
后写入者生效——求值顺序
MSBuild 按从上到下的顺序对属性求值。最后一次赋值生效:
<MyProp>value1</MyProp>
<MyProp>value2</MyProp>
<MyProp Condition="'$(MyProp)' == ''">value3</MyProp>
.targets 中的属性(较晚导入)会覆盖 .props 中的属性(较早导入)和项目文件中的属性。
常见问题
- 条件未加引号(
$(X)==true)在属性为空时会失败。两侧始终加引号。 - 覆盖 DefineConstants(
<DefineConstants>MY_CONST</DefineConstants>)会丢弃所有先前的常量。始终使用$(DefineConstants);追加。 - 硬编码绝对路径会破坏可移植性。请使用
$(MSBuildThisFileDirectory)或$([MSBuild]::NormalizePath(...))。 - 默认值缺少
Condition会使属性无法覆盖。对于作为默认值的属性,请添加Condition="'$(Prop)' == ''"。
评论
支持 Markdown