当人们谈论“.net 框架”时,他们往往会结合两个主要领域 - 运行时库和实际运行 .net 代码的虚拟机。
当您在 C# 中的 Visual Studio 中创建类库时,DLL 遵循规定的格式 - 非常粗略地说,有一个部分包含描述其中包含哪些类以及它们具有哪些功能等的元数据。描述了这些对象在二进制文件中的位置。这种常见的 .net 格式允许在 .net 语言(C#、VB.Net、F# 等)之间轻松共享库。尽管现在大部分 .net “运行时库”都是用 C# 编写的(我相信),但您可以想象其中有多少是用非托管语言编写的,但以这种规定的格式排列,以便它们可以被 .net 语言使用.
您构建的库的真正“肉”由 CIL(“通用中间语言”)组成,它有点像 .net 的汇编语言 - 同样,这种语言是所有 .net 语言的通用输出,这就是任何 .net 语言都可以使用 .net 库的原因。
使用 Microsoft SDK 中免费提供的工具“ildasm.exe”(并且可能已经在您的计算机上),您可以看到 C# 代码如何转换为元数据和 IL。作为示例,我在此答案的底部包含了一个示例。
当您运行执行 .net 代码时,通常发生的是 .net 虚拟机正在读取该 IL 并对其进行处理。这是 .net 的另一面,同样,您可以想象这可以很容易地用非托管语言编写——它“只”需要读取 VM 指令并运行它们(并与垃圾收集器集成,垃圾收集器也需要不是 .net 代码)。
我所描述的是(再次粗略地)在 Visual Studio 中构建可执行文件时会发生什么(有关更多信息,我强烈推荐 Jeffrey Richter 的“CLR via C#”一书——它非常详细且写得非常出色) .
但是,有时您可能会编写不会在 .net 环境中执行的 C# - 例如,Bridge.NET 将 C# 代码“编译”为 JavaScript,然后在浏览器中运行(生成它的团队已经努力编写用 JavaScript 编写的 .net 运行时库版本,因此 .net 库的功能和灵活性可用于生成的 JavaScript)。这是 C# 和 .net 之间分离的完美示例 - 可以为不同的“目标”编写 C#;您可以针对 .net 运行时环境(当您构建可执行文件时),也可以针对浏览器环境(当您使用 Bridge.NET 时)。
一个(非常)简单的示例类:
using System;
namespace Example
{
public class Class1
{
public void SayHello()
{
Console.WriteLine("Hello");
}
}
}
生成的元数据和 IL(通过 ildasm.exe 检索):
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly Example
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 )
.custom instance void [mscorlib]System.Reflection.AssemblyTitleAttribute::.ctor(string) = ( 01 00 0A 54 65 73 74 49 4C 44 41 53 4D 00 00 ) // ...TestILDASM..
.custom instance void [mscorlib]System.Reflection.AssemblyDescriptionAttribute::.ctor(string) = ( 01 00 00 00 00 )
.custom instance void [mscorlib]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = ( 01 00 00 00 00 )
.custom instance void [mscorlib]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = ( 01 00 00 00 00 )
.custom instance void [mscorlib]System.Reflection.AssemblyProductAttribute::.ctor(string) = ( 01 00 0A 54 65 73 74 49 4C 44 41 53 4D 00 00 ) // ...TestILDASM..
.custom instance void [mscorlib]System.Reflection.AssemblyCopyrightAttribute::.ctor(string) = ( 01 00 12 43 6F 70 79 72 69 67 68 74 20 C2 A9 20 // ...Copyright ..
20 32 30 31 36 00 00 ) // 2016..
.custom instance void [mscorlib]System.Reflection.AssemblyTrademarkAttribute::.ctor(string) = ( 01 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = ( 01 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00 24 31 39 33 32 61 32 30 65 2D 61 37 36 64 // ..$1932a20e-a76d
2D 34 36 33 35 2D 62 36 38 66 2D 36 63 35 66 36 // -4635-b68f-6c5f6
32 36 36 31 36 37 62 00 00 ) // 266167b..
.custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 01 00 07 31 2E 30 2E 30 2E 30 00 00 ) // ...1.0.0.0..
.custom instance void [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = ( 01 00 1C 2E 4E 45 54 46 72 61 6D 65 77 6F 72 6B // ....NETFramework
2C 56 65 72 73 69 6F 6E 3D 76 34 2E 35 2E 32 01 // ,Version=v4.5.2.
00 54 0E 14 46 72 61 6D 65 77 6F 72 6B 44 69 73 // .T..FrameworkDis
70 6C 61 79 4E 61 6D 65 14 2E 4E 45 54 20 46 72 // playName..NET Fr
61 6D 65 77 6F 72 6B 20 34 2E 35 2E 32 ) // amework 4.5.2
.hash algorithm 0x00008004
.ver 1:0:0:0
}
.module Example.dll
// MVID: {80A91E4C-0994-4773-9B73-2C4977BB1F17}
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x05DB0000
// =============== CLASS MEMBERS DECLARATION ===================
.class public auto ansi beforefieldinit Example.Class1
extends [mscorlib]System.Object
{
.method public hidebysig instance void
SayHello() cil managed
{
// Code size 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "Hello"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Class1::SayHello
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method Class1::.ctor
} // end of class Example.Class1
// =============================================================