Использование функций элемента по значениям метаданных

Фон: Я управляю довольно большим решением. Каждый так часто люди добавляют ссылку на DLL в проект в решении, где они должны добавить ссылку на проект. В таком случае я хочу выпустить предупреждение. Я хочу сделать это, найдя всю ссылку с 'bin\debug' в своем HintPath *. Я знаю, что ссылки - это Items в ItemGroup, с метаданными "HintPath".

Я ожидал чего-то подобного:

<Warning Text="Reference %(Reference.Identity) should be a project reference. HintPath: %(Reference.HintPath)"
         Condition="%(Reference.HintPath).IndexOf('bin\debug') != -1"/>

Однако, похоже, я не могу использовать строковую функцию IndexOf. Я пробовал много перестановок выше, без успеха.

  • Изменить: я знаю, что эта проверка не является полной, но я просто хочу уменьшить честные ошибки.

Ответы

Ответ 1

Используя MSBuild 4.0 Функции свойств, можно выполнить сравнение строк:

<Target Name="AfterBuild">

  <Message Text="Checking reference... '%(Reference.HintPath)'" Importance="high" />

  <Warning Text="Reference %(Reference.Identity) should be a project reference. HintPath: %(Reference.HintPath)"
            Condition="$([System.String]::new('%(Reference.HintPath)').Contains('\bin\$(Configuration)'))" />

</Target>

Ответ 2

Сначала не то, что ваш синтаксис не подходит для вызова функций, это должно быть:

   %(Reference.HintPath.IndexOf(...))       # Note: not supported by MSBuild

Однако функции свойств в MSBuild не разрешены в метаданных элементов, так что это тоже не поможет.

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

  <Target Name="CheckProjectReferences">
    <MSBuild 
      Projects="$(MSBuildProjectFullPath)"
      Properties="Identity=%(Reference.Identity);HintPath=%(Reference.HintPath)"
      Targets="_Warn"/>
  </Target>

  <Target Name="_Warn">
    <Warning Text="Reference $(Identity) should be a project reference. HintPath: $(HintPath)"
             Condition="$(HintPath.IndexOf('bin\debug')) != -1"/>
  </Target>

Честно говоря, я не уверен, достаточно ли этого, чтобы поймать все "нарушения". Например, вышесказанное будет работать только для bin\debug, но не для bin\debug или других вариаций с смешанным корпусом, которые функционально эквивалентны. Чтобы искать их также, вам нужно вызвать перегрузку IndexOf(string, StringComparison), но просто выполните:

   $(HintPath.IndexOf('bin\debug', System.StringComparison.OrdinalIgnoreCase))

Не будет работать, потому что разрешение перегрузки MSBuild выберет IndexOf(char, Int32) и даст вам эту ошибку:

MSB4184: выражение "bin\debug".IndexOf(bin\debug, System.StringComparison.OrdinalIgnoreCase)" не может быть оценено. Строка должна быть ровно на один символ.

Итак, вам нужно убедить это, используя непосредственную перегрузку IndexOf(String, Int32, Int32, StringComparison):

   $(HintPath.IndexOf('bin\debug', 0, 9, System.StringComparison.OrdinalIgnoreCase))

Вам может потребоваться также проверить bin\Release или другие варианты. Я не уверен, что это лучший способ выяснить, ссылка должна быть ссылкой на проект, но если вы знаете (и для определенного контроля) свою среду, это может быть осуществимо.