c# - 什么时候创建和分发 "reference assemblies"?

标签 c# .net-assembly roslyn c#-7.1

C# 7.1引入了一些新的命令行参数来帮助创建“引用程序集”。通过 documentation它输出一个程序集:

have their method bodies replaced with a single throw null body, but include all members except anonymous types.

我找到了 an interesting note that it is more stable on changes :

That means it changes less often than the full assembly--many common development activities don't change the interface, only the implementation. That means that incremental builds can be much faster- ...

还有那个it is probably necessary for roslyn itself ..

We will be introducing a second concept, which is "reference assemblies" (also called skeleton assemblies). [---] They will be used for build scenarios.

.. 无论那些“构建场景”是针对 Roslyn 的。

据我所知,对于普通的 .NET 程序集用户来说,这样的程序集可能更小,加载反射的速度也稍快一些。好的,但是:

  • 通常您还关心执行并且实现程序集已经包含来自引用程序集的所有数据,
  • 通常您并不关心加载时的微小性能差异,
  • 最重要的是 - 通常您根本没有可用(分布式)的精简引用程序集。

它的用处似乎相当小众。

所以,我想知道通用程序集生产者方面的事情 - 什么时候应该明确考虑使用那些新的编译器标志来创建引用程序集?它在 Roslyn 本身之外有任何实际用途吗?

最佳答案

此功能的动机确实是构建场景,但它们并不特定于 Roslyn; 它们也是的构建场景

构建项目时,构建引擎 (MSBuild) 需要确定构建的每个输出是否相对于其输入是最新的。例如,如果您不做任何更改,只是连续运行两次构建,则第二次不需要调用 C# 编译器:程序集已经正确。

引用程序集允许在更多场景中跳过程序集的编译步骤,因此您的构建可以更快。我认为一个例子可以帮助说明。

假设您有一个包含依赖于 A.dllB.exe 的解决方案。

B 的编译器命令行看起来像

csc.exe /out:B.exe /r:..\A\bin\A.dll Program.cs

它的输入是

  • B 的源代码(Program.cs)
  • A 的程序集。

如果您更改 A 的源代码并构建您的解决方案,编译器必须针对 A 运行,生成新的 A.dll。然后,由于 A.dll 是 B 编译的输入,因此 B 也必须重新编译。

对 A 使用引用程序集稍微改变了这一点

csc.exe /out:B.exe /r:..\A\bin\ref\A.dll Program.cs

A 的输入现在是它的引用程序集,而不是它的实现/正常程序集。

由于引用程序集小于完整程序集,因此它本身对构建时间的影响很小。但这还不足以证明此功能的合理性。重要的是编译器只关心传入引用的公共(public) API 表面。如果程序集的内部实现细节发生了变化,引用它的程序集不需要重新编译来获取新的行为。正如@Hans Passant 在评论中提到的那样,这就是 .NET Framework 本身如何在未更改的用户代码上提供兼容的性能改进和错误修复。

引用程序集功能的好处来自为使用它们所做的 MSBuild 工作。假设您更改 A 中的内部实现细节但不更改其公共(public)接口(interface)。在下一个版本中,

  • 编译器必须为 A 运行,因为 A 的源文件已更改。
  • 编译器发出 A.dll(具有更改的实现)和 ref\A.dll,这与之前的引用程序集相同。
  • 由于 ref\A.dll 与之前的输出相同,因此不会复制到 A 的输出文件夹。
  • 当 B 的编译器运行时,它发现它的输入都没有改变——B 自己的代码和 A 的引用程序集都没有改变,所以编译器不必运行。
  • B 然后将更新后的 A.dll 复制到它的输出中,并准备好以新行为运行。

在大型解决方案中,跳过下游编译的效果可能会更加复杂——更改 {ProjectName}.Utilities.dll 中的注释不再需要构建所有内容!

许多更改涉及更改公共(public) API 表面和内部实现,因此此更改不会加速所有构建,但它确实加速了许多构建。

关于c# - 什么时候创建和分发 "reference assemblies"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49777565/

相关文章:

c# - 如何在 C# 中禁用无参数构造函数

version - 在 ASP.NET Core 1.0.0 Web 应用程序中显示项目版本

asp.net-mvc - Asp.net MVC Razor View - CS1525 : Invalid expression term '.'

c# - Mysql - "order by"/Subquery 上的 Entity Framework 性能问题

c# - 如何判断 Type 是否是静态类?

c# - 创建一个支持不同单位(摄氏度、华氏度、开尔文)的温度类

c# - 无法从程序集 '...' 加载类型 'System.Web, ...'

c# - BinaryFormatter 忽略程序集版本

c# - Roslyn 脚本引擎在用作委托(delegate)时不会抛出运行时异常

c# - 无法使用 Roslyn 以编程方式将成员添加到类中