MSBuild 属性和项都用于将信息传递给任务、评估条件和存储可在整个项目文件中引用的值。
属性是名称值对。 有关详细信息,请参阅 MSBuild 属性。
项是通常表示文件的对象。 项对象可以具有关联的元数据集合。 元数据是名称值对。 有关详细信息,请参阅项。
标量和向量
由于 MSBuild 属性是只有一个字符串值的名称/值对,因此它们通常被描述为 标量。 由于 MSBuild 项类型是项列表,因此它们通常描述为 向量。 但是,在实践中,属性可以表示多个值,项类型可以有零个或一个项。
目标依赖项注入
若要查看属性如何表示多个值,请考虑将目标添加到要生成的目标列表的常见使用模式。 此列表通常由属性值表示,目标名称用分号分隔。
<PropertyGroup>
<BuildDependsOn>
BeforeBuild;
CoreBuild;
AfterBuild
</BuildDependsOn>
</PropertyGroup>
该 BuildDependsOn 属性通常用作目标 DependsOnTargets 属性的参数,有效地将其转换为项列表。 可以重写此属性以添加目标或更改目标执行顺序。 例如,
<PropertyGroup>
<BuildDependsOn>
$(BuildDependsOn);
CustomBuild;
</BuildDependsOn>
</PropertyGroup>
将 CustomBuild 目标添加到目标列表,提供 BuildDependsOn 值 BeforeBuild;CoreBuild;AfterBuild;CustomBuild。
从 MSBuild 4.0 开始,目标依赖项注入已弃用。 请改用 AfterTargets 属性 BeforeTargets 。 有关详细信息,请参阅 目标生成顺序。
字符串和项列表之间的转换
MSBuild 根据需要对项类型和字符串值执行转换。 若要查看项列表如何成为字符串值,请考虑将项类型用作 MSBuild 属性的值时会发生什么情况:
<ItemGroup>
<OutputDir Include="KeyFiles\;Certificates\" />
</ItemGroup>
<PropertyGroup>
<OutputDirList>@(OutputDir)</OutputDirList>
</PropertyGroup>
Item 类型 OutputDir 具有 Include 值为“KeyFiles\; 的属性Certificates\“. MSBuild 将此字符串分析为两个项目:KeyFiles\ 和 Certificates\。 当项类型 OutputDir 用作 OutputDirList 属性的值时,MSBuild 会将项类型转换为分号分隔字符串“KeyFiles\;Certificates\“.
任务中的属性和项
属性和项用作 MSBuild 任务的输入和输出。 有关详细信息,请参阅 任务。
属性作为属性传递给任务。 在该任务中,MSBuild 属性由一个属性类型表示,其值可以转换为字符串和从字符串转换。 支持的属性类型包括bool、、char、DateTimeDecimal、Doubleint、、和string任何可以处理的类型ChangeType。
项作为 ITaskItem 对象传递到任务。 在任务中, ItemSpec 表示项的值并 GetMetadata 检索其元数据。
可将项类型的项列表作为对象数组 ITaskItem 传递。 可以使用属性从目标 Remove 中的项列表中删除项。 由于可以从项列表中删除项,因此项目类型可能具有零项。 如果将项列表传递给任务,则任务中的代码应检查是否存在这种可能性。
属性和项评估顺序
在生成评估阶段,导入的文件会按照生成的显示顺序合并到生成中。 按以下顺序以三个传递定义属性和项:
属性的显示顺序定义和修改。
项定义按照显示的顺序定义和修改。
项的显示顺序定义和修改。
在生成的执行阶段,在目标中定义的属性和项按显示顺序在单个阶段中一起评估。
然而,这不是完整的故事。 定义属性、项定义或项时,将计算其值。 表达式计算器扩展指定值的字符串。 字符串扩展取决于生成阶段。 下面是更详细的属性和项评估顺序:
在生成评估阶段:
属性的显示顺序定义和修改。 执行属性函数。 $(PropertyName)格式的属性值在表达式中展开。 属性值设置为展开的表达式。
项定义按照显示的顺序定义和修改。 属性函数已在表达式中展开。 元数据值设置为展开的表达式。
按项类型显示的顺序定义和修改。 将展开窗体 @(ItemType) 中的项值。 项转换也会展开。 属性函数和值已在表达式中展开。 项列表和元数据值设置为展开的表达式。
在生成执行阶段:
- 在目标中定义的属性和项按显示顺序一起计算。 执行属性函数,并在表达式中扩展属性值。 项值和项转换也会展开。 属性值、项类型值和元数据值设置为展开的表达式。
计算顺序的细微效果
在生成评估阶段,属性评估在项评估之前。 不过,属性可以具有似乎依赖于项值的值。 请考虑以下脚本。
<ItemGroup>
<KeyFile Include="KeyFile.cs">
<Version>1.0.0.3</Version>
</KeyFile>
</ItemGroup>
<PropertyGroup>
<KeyFileVersion>@(KeyFile->'%(Version)')</KeyFileVersion>
</PropertyGroup>
<Target Name="AfterBuild">
<Message Text="KeyFileVersion: $(KeyFileVersion)" />
</Target>
执行消息任务将显示以下消息:
KeyFileVersion: 1.0.0.3
这是因为值 KeyFileVersion 实际上是字符串“@(KeyFile->'%(Version)'”。 首次定义属性时,未展开项和项转换,因此为 KeyFileVersion 属性赋值了未展开的字符串的值。
在生成执行阶段,在处理消息任务时,MSBuild 将展开字符串“@(KeyFile->'%(Version)”,以生成“1.0.0.3”。
请注意,即使属性和项组按顺序反转,也会显示相同的消息。
作为第二个示例,请考虑当属性组和项组位于目标内时会发生什么情况:
<Target Name="AfterBuild">
<PropertyGroup>
<KeyFileVersion>@(KeyFile->'%(Version)')</KeyFileVersion>
</PropertyGroup>
<ItemGroup>
<KeyFile Include="KeyFile.cs">
<Version>1.0.0.3</Version>
</KeyFile>
</ItemGroup>
<Message Text="KeyFileVersion: $(KeyFileVersion)" />
</Target>
消息任务显示以下消息:
KeyFileVersion:
这是因为,在生成的执行阶段,在目标中定义的属性和项组会同时从上到下进行评估。 定义时 KeyFileVersion , KeyFile 未知。 因此,项转换扩展到空字符串。
在这种情况下,反转属性和项组的顺序将还原原始消息:
<Target Name="AfterBuild">
<ItemGroup>
<KeyFile Include="KeyFile.cs">
<Version>1.0.0.3</Version>
</KeyFile>
</ItemGroup>
<PropertyGroup>
<KeyFileVersion>@(KeyFile->'%(Version)')</KeyFileVersion>
</PropertyGroup>
<Message Text="KeyFileVersion: $(KeyFileVersion)" />
</Target>
该值 KeyFileVersion 设置为“1.0.0.3”,而不是“@(KeyFile->'%(版本)'”。 消息任务显示以下消息:
KeyFileVersion: 1.0.0.3