如何将MSBuild ItemGroup成员用作单个项(如属性)?

如何将MSBuild ItemGroup成员用作单个项(如属性)?,msbuild,Msbuild,所以我已经掌握了在MSBuild中写作的诀窍 我喜欢将内容存储在ItemGroups中的想法,因为它易于迭代,并且可以有多个字段 这使它们有点像一个类(更像一个结构),但它们对目标和任务的迭代语法的响应方式就像一个lambda表达式 然而,我仍然会遇到这样的情况:我希望访问项目组中某个特定项目的值,也就是说,像访问属性一样访问它 在这种情况下,我遇到了如何在组中隔离单个项目的问题 当项目组在目标或任务中进行批处理时,由于使用元数据名称寻址或由于使用公共项目组名称寻址,您可以利用“当前”项目的值,

所以我已经掌握了在MSBuild中写作的诀窍

我喜欢将内容存储在ItemGroups中的想法,因为它易于迭代,并且可以有多个字段

这使它们有点像一个类(更像一个结构),但它们对目标和任务的迭代语法的响应方式就像一个lambda表达式

然而,我仍然会遇到这样的情况:我希望访问项目组中某个特定项目的值,也就是说,像访问属性一样访问它

在这种情况下,我遇到了如何在组中隔离单个项目的问题

当项目组在目标或任务中进行批处理时,由于使用元数据名称寻址或由于使用公共项目组名称寻址,您可以利用“当前”项目的值,即@(ItemsName)或%(MetaDataName)

但是我想做一些事情,比如:使用一个项目组作为System.Configuration类,该类包含配置文件的一部分中的条目值。因此,通常的做法是将ItemGroup本身命名为与配置文件中的节名相匹配。但是,ItemGroup不是可通过构建引擎接口访问的可寻址元素,只有项本身是可寻址的

在一个项目组中单独命名项目,而不是完全相同地命名项目,并使用Include或元数据字段来区分这些项目,这可能会更好。这使得它们的行为类似于属性,因为它们可以作为不同的项单独寻址。因此,您可以通过以下方式轻松地在条件中使用它们的值:'@(UniqueItemName->'%(Value)')

然而,可移植的特性基本上丢失了

为了缩小范围,假设我有一个配置文件,通过xml任务读取到项目组中,以便节中的元素名称成为项目组中项目的名称,并且每个配置文件元素的属性都是成为元数据的属性:

<configItemFlag name="displayDebugMessages" value="true" note="use with abandon" />
<configItemFlag name="displaySecurityValueMessages" value="false" note="use with caution" />

当我想在某个条件下测试时,我需要将其缩小到如下范围:

<Messge Text="Debug Message: you are debugging!" Condition="'@(configItemFlag->'%(Name)')' == 'displayDebugMessages' AND '@(configItemFlag->'%(Value)')' == 'true'/>

这对您正在尝试的工作有效吗

<ItemGroup>
  <ConfigItemFlag Include="displayDebugMessages">
    <Value>true</Value>
    <Note>use with abandon</Note>
  </ConfigItemFlag>
  <ConfigItemFlag Include="displaySecurityValueMessages">
    <Value>false</Value>
    <Note>use with caution</Note>
  </ConfigItemFlag>
</ItemGroup>

<Target Name="Build">
  <Message
    Condition="
      '%(ConfigItemFlag.Identity)' == 'displayDebugMessages' AND
      '%(Value)' == 'true'"
    Text="Debug Message: you are debugging, %(Note)!"
    /> 
</Target>
(对评论的回应)

…我能提供的唯一一件能够将meta用作属性的事情并不是那么好,除非目标公司在整个过程中大量使用它们。基本上,它包括通过对项目进行批处理并使用每个批创建本地属性,将每个项目展平为属性

<Target Name="BuildOne"
  Outputs="%(ConfigItemFlag.Identity)">
  <!-- flatten this batch to properties -->
  <PropertyGroup>
    <_Identity>%(ConfigItemFlag.Identity)</_Identity>
    <_Value>%(ConfigItemFlag.Value)</_Value>
    <_Note>%(ConfigItemFlag.Note)</_Note>
  </PropertyGroup>
  <!-- use meta as properties -->
  <Message
    Condition="
      '$(_Identity)' == 'displayDebugMessages' AND
      '$(_Value)' == 'true'"
    Text="Debug Message: you are debugging, $(_Note)!"
    /> 
</Target>
<Target Name="Build" DependsOnTargets="BuildOne"
  />

%(ConfigItemFlag.Identity)
%(ConfigItemFlag.Value)
%(ConfigItemFlag.Note)

您似乎遇到了msbuild脚本语言的一些限制。您是否考虑过编写一个自定义任务来执行您正在寻找的任务?这样,您就可以充分利用完整编程语言的强大功能来抵抗您想要执行的简单条件检查。

是的,这是一个好主意,我在大多数情况下都是这样做的。但是我想要的是更精简的东西,这样就减少了遍历项中元数据之间关系的语法负担,并且我可以以属性允许的更直接的方式访问要测试的值。我不得不同意。我相信您的回答表明,“扩展”包解决了一些边界情况,即开发人员希望在其构建脚本中添加一些不直接关注在普通VS解决方案或项目文件中指定的操作的内容。也就是说,扩展旨在促使MSBuild成为更通用的脚本语言。然而,您的回答指出,我所要求的是一个“intention”,即针对语言核心特性的扩展,在本例中是对核心数据结构的扩展。
<Target Name="BuildOne"
  Outputs="%(ConfigItemFlag.Identity)">
  <!-- flatten this batch to properties -->
  <PropertyGroup>
    <_Identity>%(ConfigItemFlag.Identity)</_Identity>
    <_Value>%(ConfigItemFlag.Value)</_Value>
    <_Note>%(ConfigItemFlag.Note)</_Note>
  </PropertyGroup>
  <!-- use meta as properties -->
  <Message
    Condition="
      '$(_Identity)' == 'displayDebugMessages' AND
      '$(_Value)' == 'true'"
    Text="Debug Message: you are debugging, $(_Note)!"
    /> 
</Target>
<Target Name="Build" DependsOnTargets="BuildOne"
  />