Visual Studio中MSBuild问题:C#项目先复制文件再作为内容包含
解决不同平台下C++ DLL的MSBuild引用问题
你的问题核心是MSBuild的项评估时机:所有静态定义的ItemGroup(包括你的Content项)会在项目初始化阶段就完成评估,而你的CopyFiles目标是在Build之前执行,这时候Content项早就确定了要找的文件,自然找不到后续复制的File.dll。直接在目标里添加Content项又会因为MSBuild的元数据处理规则报错,因为CopyToOutputDirectory这类元数据需要在项初始化阶段就确定好。
给你两个可行的解决方案,优先推荐第一种,更简洁:
方案一:直接根据平台条件包含对应文件夹的DLL作为Content
不需要额外的复制步骤,直接让MSBuild根据当前编译平台选择对应的源DLL,自动复制到输出目录:
<ItemGroup Condition=" '$(Platform)' == 'x86' "> <Content Include="File_32bit\File.dll"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </Content> </ItemGroup> <ItemGroup Condition=" '$(Platform)' == 'x64' "> <Content Include="File_64bit\File.dll"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </Content> </ItemGroup>
这样做的好处是:
- 跳过了中间复制到项目目录的步骤,减少冗余
- 直接利用MSBuild的条件评估,在项目初始化阶段就确定了要包含的正确DLL,完美匹配Content的处理流程
方案二:调整目标执行顺序并动态更新Content项
如果你因为某些原因必须先把DLL复制到项目目录(比如其他工具依赖项目目录下的文件),可以通过调整目标执行时机,在Content项被收集前动态更新它:
<ItemGroup> <Source32Bit Include="File_32bit\File.dll" /> <Source64Bit Include="File_64bit\File.dll" /> </ItemGroup> <Target Name="CopyFiles" BeforeTargets="SetContentDll" > <Copy SourceFiles="@(Source32Bit)" DestinationFolder="$(ProjectDir)" Condition=" '$(Platform)' == 'x86' " /> <Copy SourceFiles="@(Source64Bit)" DestinationFolder="$(ProjectDir)" Condition=" '$(Platform)' == 'x64'" /> </Target> <Target Name="SetContentDll" BeforeTargets="CollectFilesFromContent"> <!-- 先移除之前的Content项(如果有的话) --> <ItemGroup> <Content Remove="File.dll" /> <Content Include="File.dll"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </Content> </ItemGroup> </Target>
这里的关键是把CopyFiles放在SetContentDll之前,而SetContentDll又放在处理Content文件收集的CollectFilesFromContent目标之前,这样:
- 先把对应平台的DLL复制到项目目录
- 动态更新Content项,让MSBuild能找到刚复制的文件
- 后续的Content处理流程就能正确复制文件到输出目录
试一下这两种方案,第一种应该就能解决你的问题啦!
内容的提问来源于stack exchange,提问作者Baguji
相关产品推荐
相关产品推荐

