Передача массива в пользовательскую задачу MSBuild - PullRequest
6 голосов
/ 19 октября 2011

Я подумал, что это будет довольно просто, но потом понял, что нигде не могу найти никакой информации об этом.

У меня есть пользовательское задание, например:

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 ]

10 голосов
/ 20 октября 2012

@ 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 () для доступа к общеизвестным метаданным файла

6 голосов
/ 19 октября 2011

Не совсем понятно, что вы пытаетесь сделать;у вас есть код C # для пользовательской задачи, а также код MSBuild для той же задачи, что и для встроенной задачи - вы понимаете, что вам нужно сделать только одну из них, правильно?Если вы пытаетесь создать задачу в сборке, в MSBuild должен быть пустым элементом без дочерних элементов и .Если вы пытаетесь использовать встроенную задачу, вам не нужен код 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>

Если вы используете встроенный код, вам нужно указать правильные сборки MSBuild и полностью квалифицировать ParameterType.Сначала запустите его в скомпилированной сборке, даже если вы намерены использовать встроенный код.

2 голосов
/ 27 ноября 2017

Так как это в настоящее время первый удар по Google, вот другой способ сделать это (на что ссылается комментарий @ alastair-maw), когда ответил в другой теме SO :

Задачи MSBuild могут принимать ITaskItem, примитивы, строку или массив любых из них для параметров. Вы объявляете тип в своей задаче, и затем значения будут преобразованы перед передачей в задачу. Если значение не может быть преобразовано в тип, то будет сгенерировано исключение и сборка будет остановлена.

Например, если у вас есть задача, которая принимает int[] с именем Values, вы можете сделать:

<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>
...