C#基础语言知识--编译和执行过程(一)

1. 将源代码编译成托管模块
<1>使用支持CLR的任何语言创建源代码文件。
创建一个Cat.cs文件,内容如下:

using System;
namespace Animal
{
    public class Cat
    {
        public void Print()
        {
            Console.WriteLine("cat");
        }
    }
}

再创建一个Dog.cs文件,内容如下:

using System;
namespace Animal
{
    public class Dog
    {
        public void Print()
        {
            Console.WriteLine("dog");
        }
    }
}

<2>使用对应的编译器检查语法和分析源代码,生成托管模块。
现在可以将Cat.cs和Dog.cs文件生成相应的模块,利用csc.exe编译器
(Microsoft Visual Studio 2010 -> Visual Studio Tools -> Visual Studio Command Prompt(2010)..):
csc /t:module /out:D:\test\Cat.netmodule D:\test\Cat.cs
csc /t:module /out:D:\test\Dog.netmodule D:\test\Dog.cs
这个会在D:\test目录下生成两个普通模块:
Cat.netmodule
Dog.netmodule

以上执行过程如下图:
这里写图片描述

名词解释:

1 CLR
.NET FrameWork的核心是其运行库执行环境,称为公共语言运行库(Common Language Runtime)。
作用:
(1)CLR是一个类似于JVM的虚拟机,为微软的.Net产品提供运行环境。
(2)CLR上实际运行的并不是我们通常所用的编程语言(例如C#、VB等),而是一种字节码形态的“中间语言”。这意味着只要能将代码编译成这种特定的“中间语言”(MSIL),
任何语言的产品都能运行在CLR上。
(3)CLR通常被运行在Windows系统上,但是也有一些非Windows的版本。这意味着.Net也很容易实现“跨平台”。(至于为什么大家的印象中.Net的跨平台性不如Java,更多的是微软商业战略导致的)。
语言支持:
微软已经为多种语言开发了基于CLR的编译器,这些语言包括:C++/CLI、C#、Visual Basic、F#、Iron Python、 Iron Ruby和IL。除此之外,其他的一些公司和大学等机构也位一些语言开发了基于CLR的编译器,例如Ada、APL、Caml、COBOL、Eiffel、Forth、Fortran、Haskell、Lexicon、LISP、LOGO、Lua、Mercury、ML、Mondrian、Oberon、Pascal、Perl、PHP、Prolog、RPG、Scheme、Smaltak、Tcl/Tk。
CLR为不同的编程语言提供了统一的运行平台,在很大程度上对上层开发者屏蔽了语言之间才特性差异。对于CLR来说,不同语言的编译器(Compiler)就相当于一个这种语言的代码审查者(Checker),所做的工作就是检查源码语法是否正确,然后将源码编译成CLR所需要的中间语言(IL)。所以编程语言对于CLR是透明的,也就是说CLR只知道IL的存在,而不知道IL是由哪种语言编译而来。
功能
(1)基类库支持 (Base Class Library Support)
(2)内存管理 (Memory Management)
(3)线程管理 (Thread Management)
(4)垃圾回收 (Garbage Collection)
(5)安全性 (Security)
(6)类型检查 (Type Checker)
(7)异常处理 (Exception Manager)
(8)即使编译 (JIT)

2 托管模块
托管模块是标准的32位Windows可移植执行体(PE32)文件,或者是标准的64位Windows可移植执行体(PE32+)文件,它们都需要CLR才能执行。
托管模块包括:PE32或PE32+头、CLR头、元数据和IL(中间语言)代码。 下图为各个部分的说明:
托管模块的各个部分

2.1 MSIL/托管代码
中间语言(Microsoft Intermediate Language MSIL)代码, 这些代码并非专门用于任何一种操作系统, 也非专门用于C#,称为托管代码。
编译器把代码编译成中间语言(IL),而不是能直接在你的电脑上运行的机器码。中间语言(IL)在公共语言运行库(CLR)中运行,这个运行库给你的运行代码提供各种各样的服务(如内存管理和类型检查)。 .NET和C#只能产生托管代码。如果你用这类语言写程序,那么所产生的代码就是托管代码。
优点
中间语言代码与Java字节码共享一种理念:它们都是低级语言,语法很简单(使用数字代码,而不是文本代码),可以非常快速地转换为本地机器码。对于代码,这种精心设计的通用语法有很重要的优点:平台无关性、提高性能和语言的互操作性。

2.2 非托管代码
非托管代码就是在Visual Studio .NET 2002发布之前所创建的代码。例如Visual Basic 6, Visual C++ 6, 最糟糕的是,连那些依然残存在你的硬盘中、拥有超过15年历史的陈旧C编译器所产生的代码都是非托管代码。
非托管代码直接编译成目标计算机的机械码,这些代码只能运行在编译出它们的计算机上,或者是其它相同处理器或者几乎一样处理器的计算机上。非托管代码不能享受一些运行库所提供的服务,例如安全和内存管理等。如果非托管代码需要进行内存管理等服务,就必须显式地调用操作系统的接口,通常来说,它们会调用Windows SDK所提供的API来实现。
跟Visual Studio平台的其他编程语言不一样,Visual C++可以创建非托管程序。当你创建一个项目,并且选择名字以MFC,ATL或者Win32开头的项目类型,那么这个项目所产生的就是非托管程序。

两者之间的区别:
a. 托管代码是一种中间语言,运行在CLR上;
a. 非托管代码被编译为机器码,运行在机器上。

b. 托管代码独立于平台和语言,能更好的实现不同语言平台之间的兼容;
b. 非托管代码依赖于平台和语言。

c. 托管代码可享受CLR提供的服务(如安全检测、垃圾回收等),不需要自己完成这些操作;
c. 非托管代码需要自己提供安全检测、垃圾回收等操作。

2.2 元数据
元数据概述:元数据是一种二进制信息,用以对存储在公共语言运行库可移植可执行文件 (PE) 文件或存储在内存中的程序进行描述。将您的代码编译为 PE 文件时,便会将元数据插入到该文件的一部分中,而将代码转换为 Microsoft
中间语言 (MSIL)
并将其插入到该文件的另一部分中。在模块或程序集中定义和引用的每个类型和成员都将在元数据中进行说明。当执行代码时,运行库将元数据加载到内存中,并引用它来发现有关代码的类、成员、继承等信息。
元数据以非特定语言的方式描述在代码中定义的每一类型和成员。元数据存储以下信息: (1)程序集的说明
标识(名称、版本、区域性、公钥)。
导出的类型。
该程序集所依赖的其他程序集。
运行所需的安全权限。 (2)类型的说明
名称、可见性、基类和实现的接口。
成员(方法、字段、属性、事件、嵌套的类型)。 (3)属性
修饰类型和成员的其他说明性元素。

2. 将托管模块合并成程序集
CLR实际不和模块工作。它和程序集工作。
现将上诉生成的两个普通模块合并一个程序集。由于这个程序集是一个被其他程序集加载的,因此,生成的文件名可以为:Animal.dll。
**csc /out:D:\test\Animal.dll /t:library /addmodule:D:\test\Cat.netmodule;D:\test\Dog.netmodule
执行此命令之后,会在D:\test目录下生成Animal.dll**
以上执行过程如下图:
这里写图片描述
编译器默认将生成的托管代码转换成程序集。也就是说,C#编译器生成的是含有清单的托管模块。
当清单指出程序集是只由一个文件过程的时候,对于只有一个托管模块而且无资源(或数据)文件的项目,程序集就是托管模块,生成过程中无需执行任何额外的步骤。

上面的各个模块中:
主模块(负责人):Animal.dll
普通模块(成员): Cat.netmodule, Dog.netmodule。
程序集(团队):由主模块Animal.dll与普通模块Cat.netmodule、Dog.netmodule组成。但是在一般情况下我们会将Animal.dll称为程序集。特别是在IDE 的visual studio的生成的情况下,因为在IDE默认生成的dll中,已经将各个模块包含进dll中,除了dll中,并没有其他的模块文件。
在这里,我们可以运行命令:
csc /out:D:\test\Animal.dll /t:library D:\test\Cat.cs D:\test\Dog.cs直接生成Animal.dll文件
此时将不再生成Cat.netmodule与Dog.netmodule文件;

调用生成的程序集:
创建一个Program.cs文件,内容如下:

using Animal;
public class Program
{

    static void Main(string[] args)
    {
        new Dog().Print();
        new Cat().Print();
    }
}

执行命令:
csc /out:D:\test\Program.exe /R:D:\test\Animal.dll D:\test\Program.cs
将会在D:\test生成Program.exe可运行文件
注意:这里的Animal.dll文件代表的是一个程序集,如果这个程序集由多个文件组成,必须保证其他文件都存在,否则编译会失败。如当程序集由主模块Animal.dll、普通模块Cat.netmodule与Dog.netmoudle组成时,必须保证这三个文件同时存在。

在命令行中可以直接执行: Program.exe
输入结果:
dog
cat

名词解释:

程序集是一个或多个模块/资源文件的逻辑性分组。说白了就是基于.NET平台的一个 .dll 或者 .exe为后缀的文件。
一个程序集多个模块的作用:CLR只会加载被引用到的模块,没有引用的模块不会加载。因此,可以将程序集分为多个模块,运行程序时,只要保证有被引用到的模块存在即可,可以减少加载的程序集文件大小;特别是当程序集是通过网络传输加载时。

//示例:
//修改Program.cs文件,使它不再引用Cat.cs文件中的类型。
using Animal;
public class Program
{

    static void Main(string[] args)
    {
        new Dog().Print();
         // new Cat().Print();
    }
}

重新编译Program.cs文件:
csc /out:D:\test\Program.exe /R:D:\test\Animal.dll D:\test\Program.cs
现在在D:\test文件夹中具有文件如下:
这里写图片描述
运行Program.exe,结果:
这里写图片描述
现在将Cat.netmodule删除:
这里写图片描述
运行Program.exe,结果:
这里写图片描述
原因是:CLR并没有加载Cat.netmodule,因此,就算这个普通模块不存在也无所谓

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章