Трудно точно сказать, что происходит под капотом.Я не нахожусь в MSBuild, поэтому я только слабо знаком с фактической реализацией.Нам нужен разработчик MSBuild, чтобы ответить на 100% правильный ответ.Но вот что я предполагаю, что происходит (читай: остальная часть этого содержит предположения с моей стороны).
Внутри вас цель, когда вы используете выражение
Projects="$(BaseDirectory)\DebugConsoleApp\DebugConsoleApp.csproj"
MSBuild замечает, чтоу вас используется расширение свойства $ (BaseDirectory), а тип параметра для проектов в MSBuild - это массив.Также MSBuild замечает, что BaseDirectory является свойством, которое содержит элемент.Эти свойства не ведут себя как обычные свойства.Вы можете думать о них как о «виртуальных свойствах» (да, я только что придумал этот термин).Когда эти свойства используются вместо поиска значения, происходит внутренняя замена.Таким образом, ваш атрибут Projects изменится на:
Projects="@(Base->'%(FullPath)')\DebugConsoleApp\DebugConsoleApp.csproj"
Поскольку Projects - это массив, MSBuild попытается выполнить преобразование для указанного выражения.Поскольку это недопустимое преобразование, возникает ошибка.Какую ошибку вы получаете.
Теперь, чтобы обойти это, вы можете изменить свою цель сборки, чтобы она выглядела так:
<Target Name="Build">
<PropertyGroup>
<_BaseDir>$(BaseDirectory)</_BaseDir>
<_DeployDir>@(Base->'%(FullPath)')</_DeployDir>
</PropertyGroup>
<Message Text="_BaseDir: $(_BaseDir)"/>
<Message Text="DeployDirectory: $(DeployDirectory)"/>
<MSBuild Projects="$(_BaseDir)\DebugConsoleApp\DebugConsoleApp.csproj"
Properties="Configuration=$(Configuration);OutputPath=$(_Tmp2)"
ContinueOnError="false" />
<!--<MSBuild Projects="$(BaseDirectory)\DebugConsoleApp\DebugConsoleApp.csproj"
Properties="Configuration=$(Configuration);OutputPath=$(DeployDirectory)"
ContinueOnError="false" />-->
</Target>
При таком подходе я имеюсоздал группу свойств внутри самой цели и присвоил значение этих «виртуальных свойств» новым свойствам.Эти новые свойства - не виртуальные свойства, а реальные свойства, поэтому вы можете использовать их, как и ожидалось, без проблем.
Теперь перейдем к вашему вопросу: «Почему задача сообщения работает WTF? !!!" Внутри цели Hello у вас есть следующее:
<Message Text="Hello world. BaseDirectory=$(BaseDirectory), DeployDirectory=$(DeployDirectory)" />
, которое работает без проблем.Ранее я упоминал, что эти виртуальные свойства будут по существу заменены встроенными определениями, поддерживающими их, так что это фактически станет.
<Message Text="Hello world. BaseDirectory=@(Base->'%(FullPath)'), DeployDirectory=@(Base->'%(FullPath)')\Deploy" />
OK, удерживайте эту мысль.
Свойство Text
в задаче MSBuild определяется как строка, которая является скалярным значением.Если вы помните, свойство Projects в задаче MSBuild определено как ITaskItem [], так как это массив, это векторное значение.Когда @(...)
обнаруживается в свойстве векторных значений, все выражение используется для преобразования элемента .В этом случае оператор @(Base->'%(FullPath)')\DebugConsoleApp\DebugConsoleApp.csproj
не является допустимым выражением преобразования.Когда '@ (..)' находится внутри объявления свойства скалярных значений, значения сливаются в строку.Таким образом, каждый экземпляр @ (...) 'обрабатывается и объединяется в одно строковое значение.Если есть несколько значений, тогда используются разделители.
Так что, надеюсь, это объясняет поведение, которое вы видите, и это может фактически быть ошибкой.Вы можете зарегистрировать его в http://connect.microsoft.com/, и команда MSBuild выполнит его сортировку.
Подробнее о виртуальных свойствах Ранее я упоминал, что эти виртуальные свойства не ведут себя как обычные свойства вв смысле значение не ищется, но вместо этого использование $ (...) заменяется выражением свойств.Не верьте мне на слово, посмотрите сами.Вот пример файла, который я создал
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<ItemGroup>
<MyItem Include="C:\temp\01.txt"></MyItem>
</ItemGroup>
<PropertyGroup>
<MyProperty>@(MyItem->'%(FullPath)')</MyProperty>
</PropertyGroup>
<Target Name="Demo">
<Message Text="MyProperty: $(MyProperty)" />
<!-- Add to the item -->
<ItemGroup>
<MyItem Include="C:\temp\01.txt"></MyItem>
</ItemGroup>
<Message Text="MyProperty: $(MyProperty)" />
</Target>
</Project>
Здесь у меня есть список элементов MyItem , объявленный и зависимое свойство MyProperty .Внутри цели Demo я печатаю значение для MyProperty, затем добавляю другое значение в список элементов MyItem и снова распечатываю значение для MyProperty.Вот результат.
PS C:\temp\MSBuild\SO> msbuild .\Build.proj /nologo
Build started 4/26/2011 10:17:08 PM.
Project "C:\temp\MSBuild\SO\Build.proj" on node 1 (default targets).
First:
MyProperty: C:\temp\01.txt
MyProperty: C:\temp\01.txt;C:\temp\01.txt
Done Building Project "C:\temp\MSBuild\SO\Build.proj" (default targets).
Как вы можете видеть, он ведет себя так, как я сказал.