1

我在使用 MSBuild 编写脚本时遇到以下问题:我创建了一个默认项目“itemA”,其中包含两个元数据“metadata1”和“metadata2”,其中 metadata2 指的是 metadata1。

当我稍后定义 itemA 并覆盖 metadata1 时,metadata2 仍然包含 metadata1 的默认值。如何使元数据2 引用“新”元数据1?

代码说明如下:

  <ItemDefinitionGroup>
    <itemA>
      <Metadata1>default</Metadata1>
      <Metadata2>%(itemA.Metadata1)</Metadata2>
    </itemA>
  </ItemDefinitionGroup>    
  <ItemGroup>
    <itemA Include="first" >
      <Metadata1>m_data1</Metadata1>
    </itemA>
  </ItemGroup>

但是看印刷品

<Message Text="itemA.Metadata1 = %(itemA.Metadata1)" />
<Message Text="itemA.Metadata2 = %(itemA.Metadata2)" />

提供:

itemA.Metadata1 = m_data1       ***<-- correctly updated***

itemA.Metadata2 = default       ***<-- why showing the default value, not* m_data1??**

更新后如何使 itemA.Metadata2 具有与 itemA.Metadata1 相同的值?

4

2 回答 2

2

我认为这是不可能的,因为评估项目定义的顺序 - 值源 - 注意

ItemGroup 中的项目元数据在 ItemDefinitionGroup 元数据声明中没有用,因为 ItemDefinitionGroup 元素在 ItemGroup 元素之前处理。

您必须在 ItemGroup 中覆盖 itemA 的 Metadata2 值

  <ItemDefinitionGroup>
    <itemA>
      <Metadata1>default</Metadata1>
      <Metadata2>%(Metadata1)</Metadata2>
    </itemA>
  </ItemDefinitionGroup>    
  <ItemGroup>
    <itemA Include="first" >
      <Metadata1>m_data1</Metadata1>
      <Metadata2>%(Metadata1)</Metadata2>
    </itemA>
  </ItemGroup>
于 2013-07-30T16:38:05.567 回答
1

正如帕洛所说,由于 Metadata2 已经被评估,您必须明确覆盖该值。您对 Metadata1 的更改不会自动传播到初始化期间引用它的其他地方。

但是,您可以通过启动新的 MSBuild 实例并将更新后的元数据作为属性传入来“重新评估”项目的元数据。msbuild /t:Wrapper从命令行运行此项目将导致 Metadata1 和 Metadata2 打印相同的值:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <DefaultMetadata1 Condition="DefaultMetadata1==''">default</DefaultMetadata1>
  </PropertyGroup>

  <ItemDefinitionGroup>
    <itemA>
      <Metadata1>$(DefaultMetadata1)</Metadata1>
      <Metadata2>%(itemA.Metadata1)</Metadata2>
    </itemA>
  </ItemDefinitionGroup>    
  <ItemGroup>
    <itemA Include="first" >
      <Metadata1>m_data1</Metadata1>
    </itemA>
  </ItemGroup>

  <Target Name="Wrapper">       
    <MSBuild 
      Projects="$(MSBuildProjectFile)"
      Targets="Worker"
      Properties="DefaultMetadata1=%(itemA.Metadata1)"
    />
  </Target>

  <Target Name="Worker">
    <Message Text="itemA.Metadata1 = %(itemA.Metadata1)" />
    <Message Text="itemA.Metadata2 = %(itemA.Metadata2)" />
  </Target>
</Project>

这种方法的有用性取决于您要完成的工作。毫无疑问,您可以使用属性而不是项目元数据找到替代解决方案。

虽然上述解决方案适用于您描述的情况,但它很快就会失控。可能有一个更简单的解决方案可能涉及一些冗余代码。

我的建议是使用简单的解决方案并尽可能多地消除冗余,而无需发明新的方法来绕过 MSBuild 的小功能集。这里的聪明技巧可能不会在一天结束时为您节省那么多 LOC,并且可能会导致代码可读性降低,使新手更难理解发生了什么。

于 2013-08-13T05:30:35.063 回答