【问题标题】:CreateItem vs ItemGroupCreateItem 与 ItemGroup
【发布时间】:2010-10-30 13:49:41
【问题描述】:

在这样的目标内创建项目有什么区别:

<Target Name="DoStuff">
    <CreateItem Include="@(IntermediateAssembly)" >
        <Output TaskParameter="Include" ItemName="FileWrites"/>
    </CreateItem>
</Target>

像这样:

<Target Name="DoStuff">
    <ItemGroup>
        <FileWrites Include="@(IntermediateAssembly)" />
    </ItemGroup>
</Target>

您什么时候会使用其中一种,为什么?

【问题讨论】:

    标签: msbuild


    【解决方案1】:

    在 3.5 之前的 MSBuild 版本中,您无法在目标内定义属性或项目(如在第二个示例中)。所以使用了一个任务(CreateItem 和 CreateProperty)

    如果您使用的是 ToolsVersion 3.5,那么您就不需要再使用 CreateItem(不过如果您愿意,您仍然可以使用)。

    最后,他们都创建了相同的项目,具有相同的范围。使用第二种语法更具可读性,并且设置自定义元数据更容易(在我看来)。

    注意:3.5 版本的 MSBuild 随 .NET 3.5 一起安装。虽然您需要在 MSBuild 文件的 Project 标记中定义 ToolsVersion="3.5" 以使用 3.5 功能。

    如果您想知道,我从书Inside the Microsoft® Build Engine: Using MSBuild and Team Foundation Build 中获得了大部分信息,我真的很喜欢(但与任何方式无关)。

    【讨论】:

    • 是的,那本书很棒,我很喜欢 :) :) :) 感谢您的推荐。
    • 我发现了一个很大的不同:CreateItem 将通过 之类的转换操作扩展在 Include 中赋予它的通配符,而ItemGroup 声明不会扩展它。
    【解决方案2】:

    我不认为接受的答案定义了差异。

    区别在于:

    • ItemGroup 在加载 MSBuild 脚本时进行评估。
    • CreateItem 在 Target 执行时被评估

    这可能导致脚本中的 Item 值不同。

    以一个任务为例,它对目录中匹配“*.txt”的所有文件执行某些操作。如果您的 MSBuild 脚本是在 Visual Studio 中加载的,如果您使用 ItemGroup,则只有 VS 启动时存在的文件才会在 Item 中。

    如果您使用 CreateItem - 它会在执行目标时搜索所有 *.txt 文件。

    【讨论】:

    • 询问者表明两者都是从目标内部调用的。从您的回答来看,您似乎在考虑 MSBuild 3.5 之前的术语。 (当 ItemGroup 无法放置在目标内时)。如果 ItemGroup 在目标内,它就像通过 CreateItem 声明一样是动态的。 (即在运行目标时对其进行评估。)(参见“Microsoft Build Engine 内部:使用 MSBuild 和 Team Foundation Build”的第 51 页作为参考(或只是尝试一下)。
    • @Vaccano:除了 Johannes Rudolph 在对所选答案的评论中提到的例外情况外,项目组在目标内部“同样动态” - “CreateItem 将通过转换扩展在包含中赋予它的通配符operation" ... 而 ItemGroup 声明不会。
    【解决方案3】:

    CreateItem 和 CreateProperty 在 MSBuild 3.5 中已过时(当然,将始终继续工作)。很明显,我们需要相同的熟悉语法来让 ItemGroup 和 PropertyGroup 在目标中工作。

    但是目标中的 ItemGroup 有一些特殊的额外能力。它可以修改项目:例如,这将对资源列表中具有名为 Primary 且值为 true 的元数据的所有项目添加 true;仅当还没有复制元数据时:

    <ItemGroup>
      <Resources Condition=" '%(Primary)' == 'true' ">
        <Copy Condition=" '%(Copy)' == '' ">true</Copy>
      </Resources>
    </ItemGroup>
    

    另一个神奇的力量:您现在可以从列表中删除项目。此示例将从资源列表中删除所有元数据类型和值为位图的项目:

    <ItemGroup>
      <Resources Condition=" '%(Type)'=='Bitmap' " Remove="@(Resources)"/>
    </ItemGroup>
    

    这些神通目前只在内部起作用,在外部不起作用。

    关于这些东西的全部细节,我强烈推荐 Sayed Hashimi 的关于 MSBuild 的书。在亚马逊上很容易找到。

    Dan -- msbuild 团队。

    【讨论】:

      【解决方案4】:

      作为其他通过此处的其他人的附加信息:包含用于构建 MSBuild 项目的 API 的 Build-Engine 不支持将 ItemGroups 添加到 Target 的新方式。在这里你将不得不使用老式的方式。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-12
        相关资源
        最近更新 更多