31

写。提议的欺骗:由于这里的问题与链接的问题相反,我宁愿认为它不是欺骗。

首先,我确实阅读了“复制本地”和项目参考的最佳实践是什么?(也是这个),无论如何我都必须尝试一下,但是获得关于这个的一般反馈似乎是必要的,因为关于这些东西的文档太可怕了,我只在 VS2010 上,也许他们在更新的版本中改变了一些东西很高兴知道。

其次,我只对这个问题的项目参考感兴趣,因为我读到 GAC 的程序集处理方式不同,而 GAC 与我的问题无关。

第三,在阅读了建议的欺骗之后,但更多的是@Albireo 的好答案,区分文件依赖项似乎也很重要,其中依赖项引用 dll 程序集文件和项目依赖项(即我在问什么about),其中依赖项引用一个项目并隐含该项目的输出文件。

无论如何,这里的情况,我觉得有点奇怪,但仍然:

  • 2 个 C# 可执行项目
  • n C# dll 汇编项目
  • 这两个可执行文件具有不同的输出目录,因为它们将单独部署,这样它们在开发人员机器上也是独立的
  • 2 个可执行文件依赖于某些 DLL 程序集(它们可能相互依赖)
  • 有三个输出目录:
    • /x1对于可执行 1 项目
    • /x2对于可执行 2 项目
    • /lib对于所有 dll 程序集

DLL 程序集都已设置Copy Localfalse它们的项目引用,因为它们都构建到相同的输出目录。

2 个可执行项目已将它们直接引用的所有 DLL 程序集项目引用设置Copy Localtrue,以便将 DLL/x1 /x2分别复制到其中。

现在的问题是wrt。到可执行项目不直接引用但通过引用的程序集传递的DLL :通过另一个程序集传递引用的程序集复制到可执行文件的输出文件夹中,当“复制本地”设置为在第一次大会上是真的吗?

例子:

  • x1.csproj(例如输出 = x1/one.exe
    • 参考:(dlA.csproj例如输出= lib/a.dll)与Copy Local = *true*
    • (没有直接引用 b.dll)
  • dlA.csproj(例如输出= lib/a.dll
    • 参考:(dlB.csproj例如输出= lib/b.dll)与Copy Local = **false**
    • (没有直接引用 c.dll)
  • dlC.csproj(例如输出= lib/c.dll
    • (没有进一步的相关参考)

因此,我们有一个逻辑依赖关系one.exe -> a.dll -> b.dll -> c.dll,其中只有a.dll很明显被复制到的输出目录one.exe另外两个dll也会被复制到输出目录吗? 这是在某处记录的吗?


而且,是的,我试过了。而且,是的,它似乎有效,但我还没有足够努力地戳它,无论如何,我可能错过了更多的东西。(还有一个问题。任何官方文档。)

4

2 回答 2

28

区分文件依赖项似乎也很重要,其中依赖项引用 dll 程序集文件和项目依赖项(即我要问的),其中依赖项引用项目并隐含该项目的输出文件。

不是真的,不。

MSBuild 并不真正关心引用是指向解决方案中的另一个项目还是指向 DLL。

如果ProjectA依赖于ProjectB构建ProjectA ProjectB必须已经构建(并且是最新的),则 MSBuild 将提取其 DLL(而不是其 C# 代码)并将其链接到ProjectA.

为方便起见,添加项目引用而不是 DLL 是“语法糖”:这样 MSBuild 知道它必须选择引用项目的输出,无论输出是什么。

否则,您必须手动预构建依赖项,找到它的 DLL 并将其链接到项目,每当您切换构建配置、移动或重命名时都重复该过程。不太实用。

另外两个dll也会被复制到输出目录吗?

如果直接从引用程序集的项目中使用依赖项中的任何类型的元素,则将复制该引用。

一个示例可能是此解决方案布局:

  • 我的解决方案
  • MySolution.ConsoleApplication
  • MySolution.FirstDependency
  • MySolution.SecondDependency
  • MySolution.ThirdDependency
  • MySolution.FourthDependency

有了这个依赖链:

  • MySolution.ConsoleApplication
  • MySolution.FirstDependency
    • MySolution.SecondDependency
      • MySolution.ThirdDependency
      • MySolution.FourthDependency

如果您构建此解决方案,您会注意到在MySolution.ConsoleApplication输出目录中会有 DLL MySolution.FirstDependencyMySolution.SecondDependencyMySolution.ThirdDependency没有 DLL MySolution.FourthDependency

为什么会这样?当 MSBuild 构建MySolution.SecondDependency时,它注意到声明了一个依赖MySolution.FourthDependency项,但是由于它无法从代码中找到任何类型的元素的任何用法,MySolution.FourthDependencyMySolution.SecondDependency决定执行一些“优化”并MySolution.FourthDependency从输出中省略程序集。

过去,当我通过 NuGet AutoMapper 添加到“深度依赖项”时,同样的问题困扰着我:添加 AutoMapper 添加了两个程序集引用,AutoMapper并且AutoMapper.Net4,当需要执行某种操作时,第二个程序集由第一个通过反射加载在 .NET Framework 4 引入的新集合对象上。由于第二个程序集是通过反射加载的,MSBuild 认为它没有被使用,并且不会费心复制它。

所以,的,只要您直接使用它们而不是通过反射,它们就会被复制。

这是在某处记录的吗?

这种行为似乎是 MSBuild 的一个“特性”,当我遇到这个问题时,我设法找到了微软一些人的博客文章,但我现在找不到了。

于 2014-10-02T15:11:34.033 回答
20

它非常简单,与 Copy Local 没有任何关系。MSBuild 在程序集的元数据中查找程序集的依赖项。你也可以在程序集上运行 ildasm.exe 并双击 Manifest。一定要试试这个以获得洞察力。你会看到.assembly指令。编译器在构建程序集时插入,只会列出您在代码中实际使用的引用程序集。

如果 MSBuild 可以在同一目录中找到这样的程序集,那么它将自动复制它。如果没有,那么它将默默地跳过副本。

由此,您可以推断出故障模式。它不能复制非托管 DLL,它们不会出现在元数据中。它无法通过 Assembly.Load/From() 复制您间接依赖的程序集,它们也不会出现在元数据中。它无法复制尚未构建的程序集,这是构建顺序问题。它不能复制您设置为 False 的 Copy Local 属性的程序集。如果程序集存在于 GAC 中,这通常是一个有效的选择,不需要副本。

对于需要帮助的这种情况,构建后事件中的 XCOPY 可以完成工作。

于 2014-10-03T09:58:28.593 回答