WRT。拟议的欺骗行为:由于这里的问题与linked question相反,我更倾向于认为它是而不是一个骗局。
首先,我确实阅读了What is the best practice for “Copy Local” and with project references?(也是this),无论如何我都要尝试这一点,但获得一般反馈似乎是必要的,关于这些东西的docs是可怕的,我只是在VS2010上,也许他们在新版本中改变了一些很好的东西。
第二次,我只对这个问题的 项目 参考感兴趣,因为我&#39 ; ve read that assemblies from the GAC are handled differently和GAC与我的问题无关。
第三次,在阅读了建议的欺骗之后,但更多的是@Albireo的好answer,它似乎也很重要,区分文件依赖项,其中依赖项引用dll程序集文件和项目依赖项(即我要问的内容),其中依赖项引用项目并隐式输出该项目的文件。
/x1
用于可执行文件1项目/x2
用于可执行文件2项目/lib
DLL程序集所有将Copy Local
设置为false
作为项目引用,因为它们都构建到同一输出目录。
对于他们直接引用的所有DLL程序集项目引用,2个可执行项目已将Copy Local
设置为 true
,因此DLL将会分别复制到/x1
/x2
。
问题现在是wrt。对于可执行项目直接引用的不的DLL,但仅通过引用的程序集传递:将仅 的程序集通过另一个程序集传递,被复制到可执行文件的输出文件夹,当"复制本地" 在第一次装配时设置为true?
示例:
x1.csproj
(例如,输出= x1/one.exe
)
dlA.csproj
(例如输出= lib/a.dll
)Copy Local = *true*
dlA.csproj
(例如输出= lib/a.dll
)
dlB.csproj
(例如输出= lib/b.dll
)Copy Local = **false**
dlC.csproj
(例如输出= lib/c.dll
)
因此,我们有one.exe -> a.dll -> b.dll -> c.dll
的逻辑依赖关系,其中只有a.dll
显然被复制到one.exe
的输出目录。 其他两个dll是否也会被复制到输出目录? 这是否记录在某处?
而且,是的,我试过了。并且,是的,它似乎可以工作,但我还没有足够努力地戳它,无论如何可能还有更多我可能错过的东西。 (还有那个问题。任何官方文档。)
答案 0 :(得分:27)
它似乎也很重要,区分文件依赖项,其中依赖项引用dll程序集文件和项目依赖项(即我要问的内容),其中依赖项引用项目并隐式地引用该文件的输出文件项目
不是,不。
MSBuild并不关心引用是指向解决方案中的另一个项目还是指向DLL。
如果ProjectA
依赖于ProjectB
构建ProjectA
ProjectB
必须已经构建(并且是最新的),那么MSBuild将提取其DLL(而非其C#代码)并将其链接到ProjectA
。
为方便起见,添加项目引用而不是DLL是“语法糖”:这样MSBuild知道必须选择引用项目的输出,无论输出是什么。
否则,您必须手动预构建依赖项,找到其DLL并将其链接到项目,每当您切换构建配置,移动或重命名时重复该过程。不太实际。
其他两个dll是否也会被复制到输出目录?
如果直接从引用程序集的项目中使用依赖项中的任何类型的元素,那么将复制该引用。
一个例子可能是这个解决方案布局:
使用此依赖关系链:
如果您构建此解决方案,您会注意到在MySolution.ConsoleApplication
输出目录中会有MySolution.FirstDependency
,MySolution.SecondDependency
和MySolution.ThirdDependency
的DLL,但MySolution.FourthDependency
没有DLL 1}}。
为什么会这样? 当MSBuild构建MySolution.SecondDependency
时,它注意到向MySolution.FourthDependency
声明了一个依赖项,但由于它无法在MySolution.FourthDependency
中找到MySolution.SecondDependency
中任何类型元素的任何用法代码它决定执行一些“优化”并从输出中省略MySolution.FourthDependency
程序集。
当我通过NuGet AutoMapper添加“深度依赖”时,同样的问题让我感到困惑:添加AutoMapper会添加两个程序集引用,AutoMapper
和AutoMapper.Net4
,其中第二个程序集由第一次通过反射,它需要对.NET Framework 4引入的新集合对象执行某种操作。由于第二个程序集是通过反射加载的,因此MSBuild认为它未被使用,并且不需要复制它。
所以,是,只要您直接使用,就会复制它们,而不是通过反思。
这是在某处记录的吗?
这种行为似乎是MSBuild的一个“功能”,当我遇到这个问题时,我设法找到了一些来自微软的人的博客文章,但我现在再也找不到了。
答案 1 :(得分:19)
这是非常直接的,与Copy Local没有任何关系。 MSBuild查看程序集的元数据以查看程序集的依赖项。你也可以在程序集上运行ildasm.exe并双击Manifest。一定要尝试这一点来获得洞察力。您将看到.assembly
指令。编译器在构建程序集时插入,只列出代码中实际使用的引用程序集。
如果MSBuild可以在同一目录中找到这样的程序集,那么它将自动复制它。如果没有,那么它将默默地跳过副本。
由此,您可以推断出故障模式。它无法复制非托管DLL,它们不会出现在元数据中。它不能通过Assembly.Load / From()复制您具有间接依赖关系的程序集,它们也不会出现在元数据中。它无法复制尚未构建的程序集,即构建顺序问题。并且它无法复制其Copy Local属性设置为False的程序集。如果程序集存在于GAC中,通常只有一个有效的选择,不需要复制。
对于这种情况,您需要提供帮助,XCOPY在构建后的事件中完成工作。