Сравнение свойств и элементов

Свойства и элементы MSBuild применяются для передачи данных задачам, проверки условий и хранения значений, которые будут использоваться в файле проекта.

  • Свойства представляют собой пары имя-значение. Дополнительные сведения см. в разделе Свойства MSBuild.

  • Элементы — это объекты, которые обычно представляют файлы. Объекты элементов могут иметь сопоставленные коллекции метаданных. Метаданные представляют собой пары "имя — значение". Дополнительные сведения см. в разделе Элементы.

Скаляры и векторы

Поскольку свойства MSBuild являются парами "имя — значение" с одним строковым значением, они часто называются скалярами. Так как типы элементов MSBuild представляют собой списки элементов, они часто называются векторами. Однако на практике свойства могут представлять несколько значений, а в типах элементов может быть только один элемент или же элементы могут вовсе отсутствовать.

Внедрение зависимостей для целевого объекта

Чтобы проанализировать представление свойствами нескольких значений, рассмотрим общий принцип добавления целевого объекта в список целевых объектов, подлежащих сборке. Как правило, этот список представлен значением свойства, а имена целевых объектов разделены точкой с запятой.

<PropertyGroup>
    <BuildDependsOn>
        BeforeBuild;
        CoreBuild;
        AfterBuild
    </BuildDependsOn>
</PropertyGroup>

Свойство BuildDependsOn в основном используется в качестве аргумента атрибута DependsOnTargets целевого объекта и эффективно его преобразует в список элементов. Это свойство можно переопределить, чтобы добавить целевой объект или изменить порядок выполнения целевых объектов. Например, примененная к объекту директива

<PropertyGroup>
    <BuildDependsOn>
        $(BuildDependsOn);
        CustomBuild;
    </BuildDependsOn>
</PropertyGroup>

добавляет целевой объект CustomBuild в список целевых объектов, присваивая BuildDependsOn значение BeforeBuild;CoreBuild;AfterBuild;CustomBuild.

Начиная с MSBuild версии 4.0, внедрение зависимости для целевых объектов не рекомендуется. Используйте вместо него атрибуты AfterTargets и BeforeTargets. Дополнительные сведения см. в разделе Порядок сборки целевых объектов.

Преобразование между строками и списками элементов

MSBuild по мере необходимости осуществляет преобразование в типы элементов и строковые значения и наоборот. Чтобы проанализировать, как список элементов становится строковым значением, рассмотрим, что происходит, когда тип элемента используется в качестве значения свойства MSBuild.

<ItemGroup>
    <OutputDir Include="KeyFiles\;Certificates\" />
</ItemGroup>
<PropertyGroup>
    <OutputDirList>@(OutputDir)</OutputDirList>
</PropertyGroup>

Тип элемента OutputDir имеет атрибут Include со значением "KeyFiles\;Certificates\". В результате синтаксического анализа из строки выделяются два элемента: KeyFiles\ и Certificates\. Если в качестве свойства OutputDirList используется тип элемента OutputDir, MSBuild преобразует или "выравнивает" тип элемента в строку с разделителем (точка с запятой): "KeyFiles\;Certificates\".

Свойства и элементы в задачах

Свойства и элементы используются в качестве входных и выходных данных для задач MSBuild. Дополнительные сведения см. в разделе Задачи.

Свойства передаются в задачи в виде атрибутов. В рамках задачи свойство MSBuild представлено типом свойства, значение которого можно преобразовать в строку и наоборот. Поддерживаемые типы свойства включают в себя bool, char, DateTime, Decimal, Double, int, string, а также любой тип, который может обработать ChangeType.

Элементы передаются в задачи в виде объектов ITaskItem. В рамках задачи ItemSpec представляет значение элемента, а GetMetadata извлекает его метаданные.

Список элементов типа элементов можно передать в виде массива объектов ITaskItem. Начиная с .NET Framework версии 3.5, элементы можно удалять из списка элементов в целевом объекте с помощью атрибута Remove. Так как элементы можно удалить из списка элементов, тип элемента может не иметь элементов. Если список элементов передается в задачу, код в задаче должен проверить наличие такой возможности.

Порядок оценки свойств и элементов

На этапе оценки сборки импортированные файлы внедряются в сборку в порядке их расположения. Свойства и элементы определяются за три прохода в следующем порядке.

  • Свойства определяются и изменяются в порядке их расположения.

  • Определения элементов задаются и изменяются в порядке их расположения.

  • Элементы определяются и изменяются в порядке их расположения.

На этапе выполнения сборки свойства и элементы, определенные в рамках целевых объектов, оцениваются в отношении друг друга за один этап в порядке их расположения.

Однако это еще не все. Когда определены свойство, определение элемента или элемент, выполняется оценка его значения. Вычислитель выражений расширяет строку, в которой указано значение. Расширение строки зависит от этапа сборки. Ниже более подробно представлен порядок оценки свойств и элементов.

  • На этапе оценки сборки

    • Свойства определяются и изменяются в порядке их расположения. Выполняются функции свойства. В рамках выражений значения свойств в виде $(PropertyName) расширяются. Для расширенного выражения задается значение свойства.

    • Определения элементов задаются и изменяются в порядке их расположения. Функции свойств уже расширены в рамках выражений. Для расширенных выражений задаются значения метаданных.

    • Типы элементов определяются и изменяются в порядке их расположения. Значения элементов в формате @(ItemType) расширяются. Преобразования элементов также расширяются. Функции и значения свойств уже расширены в рамках выражений. Для расширенных выражений задаются значения списка элементов и метаданных.

  • На этапе выполнения сборки

    • Свойства и элементы, определенные в рамках целевых объектов, оцениваются в отношении друг друга в порядке их расположения. Выполняются функции свойств, а значения свойств расширены в рамках выражений. Преобразования значений и элементов также расширяются. Для расширенных выражений задаются значения свойств, типа элементов и метаданных.

Слабые эффекты порядка оценки

На этапе оценки сборки оценке элементов предшествует оценка свойств. Несмотря на это, у свойств могут быть значения, которые зависят от значений элементов. Рассмотрим следующий сценарий.

<ItemGroup>
    <KeyFile Include="KeyFile.cs">
        <Version>1.0.0.3</Version>
    </KeyFile>
</ItemGroup>
<PropertyGroup>
    <KeyFileVersion>@(KeyFile->'%(Version)')</KeyFileVersion>
</PropertyGroup>
<Target Name="AfterBuild">
    <Message Text="KeyFileVersion: $(KeyFileVersion)" />
</Target>

При выполнении задачи Message отображается следующее сообщение.

KeyFileVersion: 1.0.0.3

Это происходит, поскольку значением KeyFileVersion фактически является строка "@(KeyFile->'%(Version)')". Элемент и преобразования элементов не были расширены при первом определении свойства, поэтому свойству KeyFileVersion было присвоено значение нерасширенной строки.

На этапе выполнения сборки во время обработки задачи Message MSBuild расширяет строку "@(KeyFile->'%(Version)')", чтобы получилось "1.0.0.3".

Следует обратить внимание, что то же самое сообщение появится, даже если порядок групп свойств и элементов был изменен на обратный.

Во втором примере рассмотрим, что может произойти, когда группы свойств и элементов расположены в целевых объектах.

<Target Name="AfterBuild">
    <PropertyGroup>
        <KeyFileVersion>@(KeyFile->'%(Version)')</KeyFileVersion>
    </PropertyGroup>
    <ItemGroup>
        <KeyFile Include="KeyFile.cs">
            <Version>1.0.0.3</Version>
        </KeyFile>
    </ItemGroup>
    <Message Text="KeyFileVersion: $(KeyFileVersion)" />
</Target>

При выполнении задачи Message отображается следующее сообщение.

KeyFileVersion:

Это происходит потому, что на этапе выполнения сборки группы свойств и элементов, определенные в рамках целевых объектов, одновременно оцениваются сверху вниз. Когда определено значение KeyFileVersion, значение KeyFile остается неизвестным. Поэтому при преобразовании элементов расширяется пустая строка.

В этом случае при изменении порядка групп свойств и элементов на обратный восстанавливается исходное сообщение.

<Target Name="AfterBuild">
    <ItemGroup>
        <KeyFile Include="KeyFile.cs">
            <Version>1.0.0.3</Version>
        </KeyFile>
    </ItemGroup>
    <PropertyGroup>
        <KeyFileVersion>@(KeyFile->'%(Version)')</KeyFileVersion>
    </PropertyGroup>
    <Message Text="KeyFileVersion: $(KeyFileVersion)" />
</Target>

Значение KeyFileVersion задано как "1.0.0.3", а не "@(KeyFile->'%(Version)')". При выполнении задачи Message отображается следующее сообщение.

KeyFileVersion: 1.0.0.3

См. также