将数组传递给自定义MSBuild任务

时间:2011-10-19 11:45:28

标签: c# msbuild msbuild-task

我认为这很简单,但后来意识到我无法在任何地方找到任何信息。

我有一个像这样的自定义任务:

public class MyCustomTask : Task
{
    [Required]
    public string[] SomeStrings {get;set;}

    public override bool Execute()
    {
        // Do something with strings...
    }
}

匹配的MSBuild东西基本上是这样的:

<UsingTask TaskName="MyCustomTask" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildBinPath)\Microsoft.Build.Tasks.v4.0.dll">
    <ParameterGroup>
      <SomeStrings ParameterType="System.String[]" Required="true" />
    </ParameterGroup>
    <Task>
    ... 
    </Task>
</UsingTask>

<Target Name="DoSomething">
    <MyCustomTask SomeStrings="????" />
</Target>

不知道在SomeStrings参数中放什么,想想也许它会理解我是否“xxx,xxx,xxx”所以任何人都可以对此有所了解。基本场景很像标记,所以我需要一个字符串列表然后一些比较字符串,所以我需要传入2个列表/数组,但只是难倒。

3 个答案:

答案 0 :(得分:10)

@BrianKretzler完全没有使用ITaskItem,因为这是MSBuild在声明<ItemGroup>时使用的内容。

我只想用一个完整的工作示例来清除答案,因为我在尝试完成同样的事情时找到了这篇文章并帮助了我。 (搜索这些问题非常困难,因为关键字在不同的上下文中使用,所以希望这会帮助其他人)。

<UsingTask TaskName="MyCustomTask" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
    <ParameterGroup>
        <SomeStrings ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
    </ParameterGroup>
    <Task>
        <Code Type="Class" Language="cs"><![CDATA[
            using System;
            using Microsoft.Build.Framework;
            using Microsoft.Build.Utilities;

            public class MyCustomTask : Task
            {  
                public ITaskItem[] SomeStrings { get; set; }

                public override bool Execute()
                {
                    foreach (var item in SomeStrings)
                    {
                        Log.LogMessage(MessageImportance.High, 
                                       "Got item {0}",
                                       item.ItemSpec);
                        Log.LogMessage(" -> {0} -> {1}", 
                                       item.GetMetadata("Comparison"),
                                       item.GetMetadata("MoreDetail"));
                    }
                    return true;
                }
            }
        ]]></Code>
    </Task>
</UsingTask>

现在您可以使用以下方法调用此任务:

<Target Name="DoSomething">
    <ItemGroup>
       <SomeStrings Include="first string">
          <Comparison>first</Comparison>
       </SomeStrings>
       <SomeStrings Include="second string">
          <Comparison>2nd</Comparison>
          <MoreDetail>this is optional</MoreDetail>
       </SomeStrings>
    </ItemGroup>
    <MyCustomTask SomeStrings="@(SomeStrings)" />
</Target>

,输出为:

Microsoft (R) Build Engine Version 4.0.30319.1
[Microsoft .NET Framework, Version 4.0.30319.269]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 2012-10-19 5:41:22 PM.
Got first string
 -> first -> 
Got second string
 -> 2nd -> this is optional

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.12

您当然也可以使用<ItemGroup><SomeStrings Include="**\*.txt" /></ItemGroup>之类的内容,然后您将获得匹配的文件名列表,当然您可以使用GetMetadata()访问well-known file metadata

答案 1 :(得分:6)

目前尚不清楚你要做什么;你有一个自定义任务的C#代码,还有与内联任务相同任务的MSBuild代码 - 你确实意识到你只需要做其中一个,对吗?如果您尝试在程序集中创建任务,则&lt; UsingTask&gt;在你的MSBuild中应该是一个空元素,没有&lt; ParameterGroup&gt;和&lt;任务&gt;儿童。如果您尝试使用内联任务,则不需要C#代码,需要将自己的程序集指定为AssemblyFile,而不是像指定的那样指定TaskFactory。

我将参数声明为ITaskItem []类型,因此您可以将值传递为,

<MyCustomTask SomeStrings="@(SomeStrings)" />

您可以将比较字符串设置为第二个参数中的第二个项目数组,或者设置为第一个参数的元数据,例如

<ItemGroup>
   <SomeStrings Include="first string">
      <Comparison>first</Comparison>
   </SomeStrings>
   <SomeStrings Include="second string">
      <Comparison>2nd</Comparison>
   </SomeStrings>
</ItemGroup>

如果您使用的是内联代码,则需要&lt;参考&gt;正确的MSBuild程序集并完全限定ParameterType。即使您的最终目的是使用内联代码,也要先在已编译的程序集中使用它。

答案 2 :(得分:2)

由于这是目前Google上的第一个热门话题,其他方式(由@ alastair-maw评论提及)为answered in another SO thread

MSBuild任务可以接受ITaskItem,基元,字符串或任何参数的数组。您在任务中声明类型,然后在传递给任务之前转换值。如果该值无法转换为该类型,则将引发异常并且将停止构建。

例如,如果您有一个接受int[]命名值的任务,那么您可以这样做:

<Target Name="MyTarget">
    <MyTask Values="1;45;657" />
    <!-- or you can do -->
    <ItemGroup>
        <SomeValues Include="7;54;568;432;79" />
    </ItemGroup>

   <MyTask Values="@(SomeValues) />
</Target>