为什么 .NET Core 和 .NET 5 会生成可执行文件?

11

我有一个非常困惑的问题。我理解的.NET是这样的:

  • C# 应用程序(源码) ->
  • csc.exe(编译器) ->
  • .NET 应用程序(以 MSIL 形式存在)

如果是这样,为什么构建.NET应用程序的输出是Windows可执行文件?我原以为整个想法是将您的源代码编译成针对本地安装的CLR的MSIL。然而,.NET Core和.NET 5都会生成一个Windows可执行文件,它在操作系统上运行而不是在虚拟机中。

这与Java不同,Java编译为.class字节码文件(而不是.exe),这些文件确实在虚拟机上运行(或者稍后,您可以将所有类文件打包到.jar中)。

我的问题是:为什么C#编译器不会生成特定的应用程序文件类型,以在.NET上运行?例如,一个与公共语言运行时关联的.net文件?

我的最佳猜测是,Windows生成的.exe实际上并不是Windows可执行文件,而是某种.NET可执行文件。但是,在这种情况下,为什么它不能在安装.NET Core的任何平台上运行?Linux不知道.exe文件是什么。


好问题!很多新开发者都认为这是理所当然的,并接受了它“只是工作”,而没有真正调查 JIT 编译器的必要性。 - Jeremy Caney
同时,欢迎来到.NET开发!您正在学习一个令人兴奋的时代,因为在这一点上,开发模型已经非常成熟,跨平台和框架具有统一的开发体验。 - Jeremy Caney
1
.NETCore确实是这样工作的。 .jar的等效物是.dll,java.exe的等效物是dotnet.exe。 但是,在程序员习惯于运行.exe已经18年之后,.NETCore和VS并不试图太大幅度地改变这种情况。您运行的.exe是“主机”,其工作是实现VM。迟早程序员们会习惯仅分发.dll,这可能需要一段时间。 - Hans Passant
3个回答

10
正如其他答案所述,Windows上的默认设置是生成一个小型主机可执行文件,启动.NET运行时并加载适当的MSIL程序集。
有趣的一点是,MSIL程序集采用与所有Windows .exe或.dll文件相同的运行时格式(“PE” - 可移植可执行文件)打包。
早期版本的“新.NET”(.NET Core,现在是.NET 5+)只生成了可以在所有平台上运行的.dll文件,并需要用户使用dotnet theapp.dll来运行应用程序。
尽管这能够工作,但.NET Core 3.0及更高版本还提供了一个“应用程序主机”程序集作为另一种入口方式。由dotnet publish生成的代码仍然跨平台,但另外生成可执行文件具有一些优势:
- 在具有CI / CD流水线或工具期望.exe文件的大型项目中,将传统.NET Framework项目移至.NET Core需要的更改较少。 - 用户更容易在任务管理器/ ps中找到正确的程序-就像查找正确的java.exe进程一样,拥有数百个dotnet.exe进程有点困难。 - 找到或设置dotnet.exedotnet(Linux / macOS)的路径可能很麻烦。通过使用可执行文件,可以在各种位置查找运行时,并且不太依赖于正确设置的PATH环境变量。 - 在Windows上,人们可能希望更改.exe的特定于操作系统的定义,例如: - 子系统标志(GUI与控制台应用程序):.exe文件中的一个标志控制Windows是否打开控制台窗口。 Java具有java.exejavaw.exe用于控制台 vs GUI程序。 .NET Core 3.0+应用程序所需的设置可以由构建过程或项目SDK(例如WinForms、WPF)进行自定义。 - 嵌入式图标:Windows .exe文件可以包含图标。如果您希望您的应用程序(尤其是GUI应用程序)在资源管理器或任务栏中显示图标,则需要实际上可以修改图标的.exe文件。 - 嵌入Win32清单:清单文件可以控制许多东西,例如提升的访问要求(这些.exe文件会提示您允许管理员访问)。再次强调,这是通过dotnet.exe theapp.dll无法完成的事情。
请注意,目前在macOS上禁用了此可执行文件生成功能,原因是Apple的认证要求(基本上,您需要签署应用程序,然后苹果需要“验证”它以避免出现警告)。

1
生成了一个小型的主机可执行文件。该可执行文件大小为140,000字节,这个大小实在是太大了。与之相比,.NET Framework 生成的可执行文件不到5,000字节,这已经包括了“hello world”程序,而在.NET 5中,“hello world”程序仍然是一个单独的DLL文件。 - kaalus

7

它是一个常规可执行文件,但唯一包含的本地代码是一个小存根,它将调用.NET运行时。运行时将检查嵌入在该文件中的MSIL并完成其余工作。


0

因为微软希望生成的代码可以直接执行。也就是说,他们不希望

c:> rundotnet myapp

他们想要

c:> myapp

为什么呢?因为用户现在必须知道如何运行某些东西,而不仅仅是输入或点击它。因此,他们将IL封装在引导exe中,该exe加载了.NET运行时并进入了IL的主入口点。

与运行Java应用程序进行比较。

请注意,在Linux上的Mono中,您需要执行以下操作:

#: mono myapp

虽然后来他们引入了一种按照Windows方式进行的方法


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接