Quick Start
CLR(Common Language Runtime) 只是.net思想的一个方面,但确是.net的核心,它在应用程序和操作系统之间提供一个操作层,这使得 CLR 和一些解释语言比如GBsic smalltalk 还有java虚拟机很象,但是象归象,CLR决不只是一个解释器。
支持.net的编译器把不同的语言编译成 一种抽象的 中间形式,与最初的语言,目标机器,操作系统都无关。这样不同语言编写的程序会很象,不仅可以调用彼此函数,在类继承的层次上也是相同的。
不同语言还是会有很多不同点,比如大小写等。必须制定一套规则让这些语言融洽相处。 比如 c# 中定义两个变量 a和A 在vb.net中就很难区分。同样如果你用ILasm写了个全局函数,C# 中就没办法调用,因为C#中没有全局函数的概念。
这一套保证不同语言编写的 .net 程序协作运行的规则就是CLS(commom language specification),它限制了命名规则,数据类型,函数类型,和其他一些东西,让不同的语言显得相同。 当然,CLS 只是一个建议,就算你的程序不符合CLS的要求,它仍然可以有效得在CLR中运行,只是它不能保证能和其他语言在各方面协作运行。
.net程序的这种中间形式包括两大部分:元数据(metadata)和托管代码(managed code)。 元数据是关于应用程序各个组成部分的描述系统,包括类,类成员和属性,全局的定义等还有他们之间的关系。
托管代码就是将应用程序中的方法编码成一种抽象的中间形式叫做MSIL(Microsoft Intermediate Language) 或 CIL(Common Intermediate Language)。简单起见,后面我们只用IL表示MSIL/CIL,除非有特别说明。
托管代码被运行时管理,Common Language Runtime Management 包括3个部分(当然并不仅是这3部分):类型控制,结构化异常处理和垃圾回收。类型控制包括在运行时检验和转换成员的类型;结构化的异常处理在功能上很象非托管代码异常处理,不过它是由运行时执行而不是操作系统;垃圾回收包括自动得认出并销毁没有被使用的对象。
一个.net应用程序通常包括一个或几个可执行体,每一个可执行体都包括元数据和托管代码,托管代码是可选的,因为可以构造出一些不需要函数的可执行体。当然这种东西只能当作应用程序的附属的部分。
一个托管的.net应用程序简单的说就是一个装配(Assemblies),而可执行体被叫做模块。你可以构建单模块的装配,也可以构建多模块的装配。每个装配都包括一个主模块,在它的元数据中装载着装配身份的信息。
托管的.net可执行体包括两个主要部分,元数据和托管代码,正好对应CLR的两个子系统:装载者Loader和即时编译器JIT Compiler。
简单的说装载者读元数据并产生一份内部的描述,然后按照需要安排类及其成员。当然那些没有被应用的类是不会被安排的。加载一个类时,装载者会对元数据的关系进行一系列的检查。
即时编译器依赖装载者的结果并将IL描述转换为针对底层平台的本地代码。因为运行时并不是一个解释器,JIT会吧IL编译成本地代码放在内存中然后执行本地代码。 即使编译 也时按需要进行的,只有被调用的函数才会被编译。编译后的代码被放在内存中,如果内存不足,一些函数会被丢弃,等调用的时候再重新编译该函数。
IL代码也可以被预编译成本地代码存储在硬盘或其他介质中,以后加载的时候就不需要再编译,直接加载本地代码。不过IL的那个版本也不能丢了,因为原生代码并不包括元数据。
A Simple Exsample
.assembly extern mscorlib { } //元数据 表示要应用哪些外部的装配 还可以加上一些其他选项 比如version culture等
.assembly OddOrEven { } //定义该装配的名字
.module OddOrEven.exe //定义模块 完整的文件名 不能包括路径
//----------- Class declaration
.namespace Odd.or { //定义命名空间
.class public auto ansi Even extends [mscorlib]System.Object {
//public:visibility auto:LayerOut Style ansi:字符串转换模式(?) Even:name extends:继承
//----------- Field declaration
.field public static int32 val
//----------- Method declaration
.method public static void check( ) cil managed {
.entrypoint
.locals init (int32 Retval)
AskForNumber:
ldstr "Enter a number"
call void [mscorlib]System.Console::WriteLine(string)
call string [mscorlib]System.Console::ReadLine()
ldsflda valuetype CharArray8 Format
ldsflda int32 Odd.or.Even::val
call vararg int32 sscanf(string,int8*,...,int32*)
stloc Retval
ldloc Retval
brfalse Error
ldsfld int32 Odd.or.Even::val
ldc.i4 1
and
brfalse ItsEven
ldstr "odd!"
br PrintAndReturn
ItsEven:
ldstr "even!"
br PrintAndReturn
Error:
ldstr "How rude!"
PrintAndReturn:
call void [mscorlib]System.Console::WriteLine(string)
ldloc Retval
brtrue AskForNumber
ret
} // End of method
} // End of class
} // End of namespace
//----------- Global items
.field public static valuetype CharArray8 Format at FormatData
//----------- Data declaration
.data FormatData = bytearray(25 64 00 00 00 00 00 00) //% d . . . . . .
//----------- Value type as placeholder
.class public explicit CharArray8
extends [mscorlib]System.ValueType { .size 8 }
//----------- Calling unmanaged code
.method public static pinvokeimpl("msvcrt.dll" cdecl)
vararg int32 sscanf(string,int8*) cil managed { }
在IL中类可以分开来定义 比如你现在定义一部分用{括起来,然后在模块的另一个地方继续定义。不过不能跨模块/。
待续.....