33

我有以下项目结构:

Library1 <--[project reference]-- Library2 <--[ref]-- Executable
--------                          --------            ----------
ContentFile                      .cs files           .cs files
.cs files

所有项目引用都具有 CopyLocal = true。

当我构建项目时,ContentFile被复制到Library2的输出目录,而不是Executable的输出目录,这意味着ContentFile应用程序运行时缺少可执行文件。

为什么内容文件被复制到Library2's 的输出目录,而不是Executable's?有没有办法将它也复制到后者(我想在没有构建事件的情况下这样做,因为我相信人们会忘记这一点)?

我正在寻找一个合理且可维护的解决方案;在添加新项目或新的间接引用的内容文件时需要最少的努力,因此不太可能简单地忘记这样做。

使用构建后事件(如xcopy ../Library/bin/Debug/SomeDll.dll bin/Debug);并手动将项目的输出目录设置为$(SolutionDir)/bin/...而不是默认(基于每个项目),都很快变得一团糟。在“主项目”中添加内容文件作为链接也太乏味了。如果 C# 的输出文件具有与 Visual C++ 相同的默认设置(即$SolutionDir/$Platform/$Configuration),那会很好,但事实并非如此。

我还考虑过根本不使用标准的 MSBuild 程序并编写自定义构建目标(例如在 Atmel Studio 中使用 gcc),但我并没有走多远。此外,我希望 Visual Studio 的标准“构建”和“调试”命令能够像往常一样工作。


更新:

这里有更多关于我在做什么的细节。

我有一个Executable项目的解决方案。此外,还有很多项目可以称为Plugins。通过托管项目引用Executable引用所有这些。Plugin

由于插件项目是为可执行文件量身定制的,但可能具有可重用的组件,因此主要功能通常在External项目中实现,而Plugin项目只是一个包装器(尽管并非总是如此)。

所述External项目有时使用第三方提供的本地 DLL。然后将这些 DLLExternal作为内容文件添加到项目中并Copy to output dir设置为Copy always. 所以结构看起来像上图:

External <---------------[is not aware of]--------------------+
--------                                                      |
.cs files <--[reference]-- PluginWrapper <--[reference]-- Executable
"Native DLL"               -------------                  ----------
                           .cs files                      .cs files

奇怪的是,“Native DLL”被复制到External's 的输出目录(显然),还有 PluginWrapper's,但不是 Executable's。

然后,开发人员的工作流程将是编写一个External作为完全隔离的实体工作的一个(它们经常被重用),用 a 包装它PluginWrapper,然后只添加一个对 to 的项目PluginWrapper引用Executable。我觉得很奇怪,这显然是一件不寻常的事情。

我认为也许编辑Executable的 MSBuild 目标 XML(也包括间接引用的内容文件)可以解决问题。

我可能想考虑按照建议将 DLL 作为嵌入式资源添加到项目中,但是像这样嵌入本机 DLL 对我来说似乎很奇怪。最后,正如 Brenda Bell 建议的那样,通过从上图中删除“[不知道]”并添加对 的项目引用来更改开发人员的工作流程External可能是最明智的解决方案,即使不是理想的解决方案。

更新 2

请注意,嵌入式资源的想法可能不适用于所有情况。如果需要在可执行文件的目录中放置依赖项(不是 cwd 或任何东西),那么这可能无法正常工作,因为安装文件夹中缺少管理员权限(从嵌入式资源中解压缩文件)。听起来很奇怪,但这是我们使用的第 3 方库之一的严重问题。

4

5 回答 5

23

将 Library1 引用添加到 Executable 项目。

于 2012-12-05T01:22:04.000 回答
5

编辑:

您可以将所有内容放在一个单独的项目中,将其所有条目设置为“内容”和“始终复制”,并从外部和可执行文件中引用该项目

-

IMO 您正在寻找嵌入式资源,而不是内容文件。

当您编译库 1 时,内容文件被放置在其 bin 文件夹中。编译库 2 时,编译器会识别引用的代码并包含它(库 1.dll),但无法识别内容文件,因为它们在库 2 中的任何地方都没有提及。将库 2 链接到可执行文件时也是如此。

如果您的内容文件相对较小(图标、模板等),并且您不希望在丢失源代码的情况下需要编辑它们,那么您可以将它们作为资源嵌入并提供一个公共方法来返回内容,例如:

 public static Stream GetResourceContent(string rName){
     string resName = System.Reflection.Assembly
         .GetExecutingAssembly().GetManifestResourceNames()
         .FirstOrDefault(rn => rn.EndsWith("."+rName));
    if(resName!=null)
        return System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resName);
    else
        return null;
}

如果您的内容必然会更改,例如模板等,请考虑在可执行项目中包含一份副本

于 2012-12-07T15:58:43.527 回答
3

另一种选择是将 ContentFile 作为资源嵌入 Library1 程序集中并使用 Assembly.GetManifestResource() 提取它。

有关更多信息,请参阅这些链接:

http://www.attilan.com/2006/08/accessing-embedded-resources-using.html

http://blogs.msdn.com/b/alexdan/archive/2007/12/19/loading-embedded-resources-in-c-using-getmanifestresourcestream.aspx

于 2012-12-05T03:47:32.483 回答
1

Brenda 回答的一种变体是将Library1 的内容文件作为链接添加到可执行项目中。您仍然拥有项目中的条目,但您不需要管理每个文件的多个副本。

于 2018-02-14T01:23:52.973 回答
0

可能是您仅从 XAML 文件中引用 Library1,在这种情况下,Visual Studio 无法识别该用法。在代码中添加引用,例如通过应用 name 属性

于 2019-01-25T11:07:27.017 回答