C#编译/构建是一个增量过程

本文关键字:一个 过程 编译 构建 | 更新日期: 2023-09-27 18:28:47

我们的解决方案包含许多C#项目。它们之间存在复杂的依赖关系,例如项目A/B/C、A依赖B、B依赖C。如果我更改项目C中的一个文件,然后重建解决方案,项目A、B、C将一起重建。

在C++中,构建包含编译和链接两个过程。如果我更改了项目C中的一个文件,然后我构建了解决方案,A和B中的相关文件将被编译(其他文件不会被编译,它们的.obj将在链接过程中重用),然后进行链接。

在java中,只有项目C中更改后的文件会被重新编译,其他文件会被保留,然后打包到.jar。它重用以前的工作输出(没有更改文件的.class)。

总之,C#不重用任何以前的工作输出。它没有任何中间文件,就像Java的.class和C++的.obj一样。所以在这一点上,我觉得C#没有进行增量构建过程。一些微小的更改将导致一个巨大的构建过程。我不明白为什么C#不使用以前的工作输出来加速构建过程。

我不确定我对C#编译/构建过程的理解是否正确。你能帮我解释一下吗?非常感谢。

C#编译/构建是一个增量过程

C#编译器进行增量编译,我不确定你从哪里得到它不这样做的想法。也许,由于解决方案的复杂性,您没有正确理解依赖关系,您认为不需要重新编译的项目实际上是必要的。

检查编译器行为的最好方法是创建一个简单的伪解决方案并对其进行处理:

设置:

  1. 创建一个空的Visual Studio C#解决方案
  2. 添加任意两个项目,AB
  3. 将项目B作为项目A的参考
  4. B中实现一个类FooInB,并在A BarInA中的另一个类中使用它

现在让我们玩一下这个设置:

  1. 编译解决方案。您将看到这两个项目都在编译
  2. 再次编译解决方案。您将看到没有一个项目编译,这两个项目都是最新的
  3. 更改BarInA中的实现并重新编译。你将看到只有一个项目编译A。没有必要以再次编译CCD_ 11
  4. 更改FooInB中的实现并进行最后一次编译。您将看到这两个项目都在编译。这种行为是正确的,A依赖于B,因此B中的任何更改都必须重新编译A,以确保它指向B的最新版本。在理论世界中,C#编译器可以检测B中的更改是否对A没有影响,从而可以再次"优化"构建A,这将是一个噩梦般的场景,每个项目都可能引用不同且过时的程序集版本

也就是说,我想指出的是,AFAIK,C#编译器只会在项目级别执行增量编译。我不知道在任何给定的程序集中有任何类级别的增量编译优化。对编译器内部工作有更深入了解的人可能能够澄清这种行为。

你是对的。

如果项目A依赖于项目B。依赖项目B的更改确实需要重新编译项目A。

如果项目B依赖于项目C。项目B中的更改不会使项目C重新编译。

在Java中,一个类/文件被编译为一个.class文件。因此,当单个文件发生更改时,整个项目不需要重新编译。

在分发之前,这些.class文件被合并到一个.jar中。如果一个.class的文件发生了变化,那么整个.jar也需要重新组装。

在.Net中,您可以立即将项目编译为程序集(.dll或.exe),因此单个文件更改需要重新编译整个程序集。

在Java环境中也可以看到同样的行为,其中.jar(或.apk等依赖项)用于运行/调试应用程序。整个.jar在开发过程中也是必需的。当单个文件发生更改时,整个项目都会重新编译。

您可以始终将项目放置在解决方案之外。并且只添加对他们生成的.dll的引用。这将最大限度地减少编译时间。

好的。。你实际上走在了正确的轨道上。。如果解决方案中有3个项目,则可以将一个项目引用到另一个项目。这意味着项目A依赖于项目B依赖于项目C。

当您构建一个项目时,所有构建的文件和dll(来自构建后事件)都会出现在该项目的bin文件夹中。

因此,当您构建项目A时,项目C将首先构建(因为A->B->C)。项目B使用项目C的已构建组件,并创建自己的组件。项目A使用B和C的组件并创建自己的组件。

正因为如此,如果你只构建项目A,如果引用正确,你会在项目A的bin文件夹中看到B和C的所有构建文件。

我有一个包含许多项目甚至更多跨项目引用的解决方案。

为了简单起见,假设我有项目ABC

  • A是我的主桌面exe,它引用了BC
  • B包含窗体并引用C
  • C包含体系结构和数据库逻辑

我的主要问题是:B编译大约需要四十五秒。现在假设我只更改了C中的一小行代码,编译器将编译C,之后它将编译B,而不是A由于我主要在C中更改代码,它编译得很快,所以我总是要等待B编译。

我从红门发现了.NET Daemon。这是一个更改生成过程的工具,并且只有在C中的公共API更改时才会重新生成B。这可能会对您的构建过程产生巨大影响。我想说,根据我的个人经验,它节省了大约80%的建筑时间。。

然而,我只是看了看,他们不再卖了:https://www.red-gate.com/products/dotnet-development/dotnet-demon/

Visual Studio 2015将推出微软新的Roslyn编译器,我们认为这些改进使得.NET Devon变得多余。

我仍在使用Visual Studio 2013,但我认为对构建过程的初步观察以及关于.NET构建的其他答案可能不再适用于带有Roslyn的Visual Studio 2015。也许它的行为更像dotnet的deamon构建。

附带说明:我的新项目使用IOC容器,所有内容都连接在主项目中,没有太多的跨项目引用。这也将改善构建过程,因为几乎所有的东西都可以并行构建。

C#的所有版本(MSBuild实际上)都支持非依赖项目的增量编译。

VS2003中的C#支持项目中的增量编译。有一个用户声音建议将该功能引入最新的C#版本。

我已经用Jenkins MSBuild插件进行了测试,增量构建按预期运行,只有更改后的项目才会重新编译。

我想要的是进行增量部署,只部署这些更改/重新编译的dll。现在,我如何有效地找到重新编译的dll。