【问题标题】:References into separate subfolder引用到单独的子文件夹
【发布时间】:2024-01-19 10:07:02
【问题描述】:

我花了几天的时间,终于找到了一个似乎可行的解决方案。但是,它似乎有点脆弱,或者可能是不明智的。

我希望将所有非系统引用的程序集(当前使用的项目库由 NuGet 管理)包含在构建输出的“libs”子文件夹中。

我的 csproj 文件底部包含的以下 sn-p 执行此操作(基于谷歌搜索和我在这里找到的几个问题。)

  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
       Other similar extension points exist, see Microsoft.Common.targets. -->
  <Target Name="BeforeBuild">
    <Message Text="### Removing existing 'lib' folder" Importance="high" />
    <RemoveDir Directories="$(TargetDir)libs" />
  </Target>
  <Target Name="MoveLibrariesOnBuild" AfterTargets="Build">
    <ItemGroup>
        <Libraries Include="%(Reference.HintPath)" >
           <MissingHintPath>$([MSBuild]::ValueOrDefault('%(Reference.HintPath)', '').Equals(''))</MissingHintPath>         
        </Libraries>
    </ItemGroup>
    <Message Text="### Moving libraries to 'libs' ###" Importance="high" />
    <Copy SourceFiles="@(Libraries)" 
            DestinationFiles="$(TargetDir)libs\%(Filename).dll" 
            Condition="%(Libraries.MissingHintPath) == False" 
            SkipUnchangedFiles="false" 
            OverwriteReadOnlyFiles="true" />
  </Target>
</Project>

我尝试使用 Reference.Identity 和 Reference.Filename,但 Filename 还包含版本、文化等信息(因此它不会被正确重命名,除非我尝试使用内联字符串替换来搞乱。)

你的想法?有没有更简单的方法,我是不是想多了?

我根据参考建立一个列表,并使用 HintPath(仅存在于非标准程序集)作为我应该包含的标志。然后,在我的 MoveLibrariesOnBuild 目标中,MissingHintPath 用作条件标志。

根据我找到的建议,我已经避免使用 CopyLocal(它为引用生成 True 属性)。例如What is the best practice for "Copy Local" and with project references?

我看到其他人问过类似的问题,但似乎没有一个回答或完整。也许,在社区的一些批评下,这可以成为一个有用的资源。

PS:我也尝试使用 xcopy 和 robocopy 使用项目构建事件,但事实证明这些更不可靠(并且难以调试)。

此外,这依赖于设置探测路径,如此处所述,C#: Custom assembly directory

PPS:如果您在删除/覆盖文件时遇到“文件正在使用”问题,您可能需要取消选中“启用 Visual Studio 托管进程”,如here所述,

【问题讨论】:

  • 程序员可能会痴迷于组织他们的项目。这是非常有害的,CLR喜欢你这样做。不得不依赖 .config 文件只会增加一些额外的故障模式和冷启动延迟,而没有任何可以想象的好处。
  • 好处是利益相关者需要的时候,担心用户会觉得翻阅一堆文件太麻烦,宁愿尽可能少的让他们处理。我只是在任何地方都找不到这样做的好方法,并认为其他人也可能会发现它也很有用(如果有更好的方法,可能会更正一次。)但是,也许就您而言,原因并不多有关如何执行此操作的文档,因为不建议这样做。

标签: c# visual-studio msbuild


【解决方案1】:

这是一个老问题,但 MSBuild 在某处为项目引用引入了一个看似未记录的“DestinationSubDirectory”元数据选项。我之所以知道这一点,是因为我花了很多时间来分解 Microsoft.Common.targets 本身以了解它是如何工作的。

这样使用:

  <ItemGroup>
    <ProjectReference Include="..\Utilities\Company.Project.Utilities.csproj">
      <Project>{ea7de0b6-aaba-42e7-97ae-bb33877db2a4}</Project>
      <Name>Company.Project.Utilities</Name>
      <DestinationSubDirectory>libs\</DestinationSubDirectory>
    </ProjectReference>
  </ItemGroup>

您的 dll 将被复制到位于项目输出目录中的“libs”子文件夹中。

【讨论】:

  • 这是否适用于PackageReference?还是只有ProjectReference
  • @ZevSpitz 不确定!我的项目不支持与 PackageReference 一起使用,因此我无法尝试,但如果您已经在使用它们,编辑 MSBuild 以添加 DestinationSubDirectory 子元素非常简单。我很想知道它是否有效!
  • @bwerks - 我已经尝试过了,但对我不起作用。请在此处查看我的问题:*.com/questions/63986659/…