Collections and $, @, % Variable References in MSBuild

A very useful and illuminating article:

MSBuild: PropertyGroup, ItemGroup, Item Metadata, and crazy $@% syntax

It also expertly articulates a common feeling:

It brings me great joy that the title of this blog post is both technically accurate and evokes the type of comic-book language I use when trying to figure out MSBuild variable syntax.

It expounds on how to express discrete items, lists, and dictionaries as well as how to refer to them; even implicitly looping over collections.

At the high-level:

  • $: Refers to scalar values. Renders an empty-string for collections.
  • @: Can be used to pass collections or flatten a collection into semicolon-delimited values if used in a scalar context (like embedding in a message task). Note that the individual values will first be normalized by expanding by semicolon and then be flattened by semicolon. So, extraneous semicolons will in fact be removed.
  • %: Expand the given task into N-tasks for each item in a collection.

It’s worth mentioning that %(VariableName) will not expand in such a way that it would result in doing the same thing twice.

For example, I have a list of two assemblies and two XML files of the same two names and would like to print them:

<Target Name="BeforeBuild">
  <ItemGroup>
    <File Include="$(MSBuildProjectDirectory)\AncillaryAssemblies\*.*" />
  </ItemGroup>
  <Message Text="Inner file: %(File.Filename)" />
</Target>

Output:

1>  Inner file: EntityFramework
1>  Inner file: EntityFramework.SqlServer

However, if I were to print the extensions, as well:

<Target Name="BeforeBuild">
  <ItemGroup>
    <File Include="$(MSBuildProjectDirectory)\AncillaryAssemblies\*.*" />
  </ItemGroup>
  <Message Text="Inner file: %(File.Filename) %(File.Extension)" />
</Target>

Output:

1>  Inner file: EntityFramework .dll
1>  Inner file: EntityFramework.SqlServer .dll
1>  Inner file: EntityFramework.SqlServer .xml
1>  Inner file: EntityFramework .xml

Something to keep in mind.

Advertisement