解释
对于示例场景,假设我们有项目 X、程序集 A 和程序集 B。程序集 A 引用程序集 B,因此项目 X 包含对 A 和 B 的引用。此外,项目 X 包含引用程序集 A 的代码(例如 A.一些函数())。现在,您创建一个引用项目 X 的新项目 Y。
所以依赖链看起来像这样:Y => X => A => B
Visual Studio / MSBuild 试图变得聪明,只将引用引入项目 Y,它检测到项目 X 需要它;它这样做是为了避免项目 Y 中的引用污染。问题是,由于项目 X 实际上不包含任何明确使用程序集 B 的代码(例如 B.SomeFunction()),VS/MSBuild 没有检测到 B 是必需的通过 X,因此不会将其复制到项目 Y 的 bin 目录中;它只复制 X 和 A 程序集。
解决方案
你有两个选项来解决这个问题,这两个选项都会导致程序集 B 被复制到项目 Y 的 bin 目录中:
- 在项目 Y 中添加对程序集 B 的引用。
- 将虚拟代码添加到项目 X 中使用程序集 B 的文件中。
出于几个原因,我个人更喜欢选项 2。
- 如果您将来添加另一个引用项目 X 的项目,则不必记住还包括对程序集 B 的引用(就像您必须使用选项 1 一样)。
- 您可以有明确的评论说明为什么需要有虚拟代码而不是删除它。因此,如果有人不小心删除了代码(比如使用查找未使用代码的重构工具),您可以轻松地从源代码管理中看到代码是必需的并恢复它。如果您使用选项 1 并且有人使用重构工具来清理未使用的引用,那么您没有任何评论;您只会看到从 .csproj 文件中删除了一个引用。
这是我遇到这种情况时通常添加的“虚拟代码”示例。
// DO NOT DELETE THIS CODE UNLESS WE NO LONGER REQUIRE ASSEMBLY A!!!
private void DummyFunctionToMakeSureReferencesGetCopiedProperly_DO_NOT_DELETE_THIS_CODE()
{
// Assembly A is used by this file, and that assembly depends on assembly B,
// but this project does not have any code that explicitly references assembly B. Therefore, when another project references
// this project, this project's assembly and the assembly A get copied to the project's bin directory, but not
// assembly B. So in order to get the required assembly B copied over, we add some dummy code here (that never
// gets called) that references assembly B; this will flag VS/MSBuild to copy the required assembly B over as well.
var dummyType = typeof(B.SomeClass);
Console.WriteLine(dummyType.FullName);
}