用Visual Studio等IDE写C#的Hello World非常简单,但脱离了IDE你能不能打印出Hello World呢?这不是说工作时脱离IDE,而是学习一下CLR的执行模型.

  Hello World

  1. 新建一个记事本,输入如下代码,另存为HelloWorld.txt。

    using System;
    namespace HelloWorld
    {
    class Program
    {
    static void Main(string[] args) {
    Console.WriteLine("Hello World!");
    Console.ReadKey();
    }
    }
    }
  2. 打开Visual Studio 2008(2005,2010) 命令提示程序

  3. 切换到HelloWorld.txt的目录 
  4. 运行命令:csc /out:Hello.exe HelloWorld.txt 

  如无意外,将会编译出Hello.exe,能打印出Hello World。

  CLR执行模型-编译期

  CLR程序的执行过程大致分为两步,编译期和运行期,编译期过程大致如下图:

  其中编译期逻辑上也可分为两步:

  1. CLR(C#)编译器接受源代码文件,并编译为托管模块。托管模块包括IL代码、元数据、CLR头等组成部分。上面的例子中就是将HelloWorld.txt编译成托管模块。
  2. 一般程序集都会包含很多源代码文件(这里只有HelloWorld.txt)和资源文件,第二步就是把各个源代码文件和资源文件对应编译结果合并成程序集。

  执行上面两步就可以得到一个XX.dll或XX.exe的程序集,就像上面的Hello.exe。

  编译器如何知道要编译成托管模块还是资源文件?其实是必须明确告诉编译器每个文件的怎么编译,这个对应Visual Studio的文件属性的生成操作.

  右击任何Visual Studio解决资源方案的文件-->属性-->生成操作:

  指定Class1为嵌入的资源,用ILSpy查看会发现只是把Class1嵌入到程序集中,名称为:命名空间.文件名:

  你甚至可以将一张图片设为编译让编译器试图去编译它,不过会报错。

  运行期

  上面生成了程序集,程序集内的是IL代码,它还不是可运行的代码。IL是与CPU无关的机器语言,直到程序集被调用,才会由JIT(Just-in-Time,实时)编译器编译为本机代码(CPU指令)。在运行时,CLR执行如下步骤:

  1. 检查程序集的安全特性;
  2. 在内存中分配空间;
  3. 把程序集中的可执行代码发送给JIT编译器,把其中一部分编译成本机代码(CPU指令)。

  程序集的可执行代码在需要的时候由JIT编译器编译,然后本机代码(CPU指令)就被缓存以备后来的程序中执行。一旦应用程序终止,编译好的本机代码也会被丢弃。

  例如如果将上面的代码改为:

static void Main(string[] args) {
Console.WriteLine("Hello");
Console.WriteLine("World!");
Console.ReadKey();
}

  第一个WriteLine需要先JIT编译,再执行。而由于已编译WriteLine的代码,所以第二个WriteLine会直接执行内存块中的代码,跳过JIT编译。

  由于分配内存、JIT编译过程等,所以程序会在第一次运行时造成一些性能损失,写ASP.NET时这种感觉特变明显,按了F5会等很久才会显示首页。

  下面模拟感受这个过程。用一大堆类延长内存分配的时间,参考这个文件HelloWorld.cs(博客园不支持txt格式):

  再次运行命令:csc /out:Hello.exe HelloWorld.txt,得到Hello.exe,执行时发现有一定的延迟才会打印出Hello World。

  生成本机代码

  使用.NET提供的NGen.exe,可以将IL代码编译成本机代码,可以解决上面的问题。NGen.exe有两个作用:

  1. 加快应用程序的启动速度。因为代码已编译为本机代码,运行时不需要再花时间编译。
  2. 减少应用程序的程序集。如果一个程序集会同时加载多个进程,NGen.exe会将IL编译成本机代码,并保存到一个单独的文件中。这样就可以通过"内存映射"的方式,同时映射到多个进程中,使代码共享,避免每个进程一份代码。

  再次运行 Visual Studio 2008(2005,2010) 命令提示程序

  运行如下命令:ngen install Hello.exe:


  命令完成(在我的机器大概要10秒左右,到能再次输入命令才完成)后,运行Hello.exe会发现马上就能打印出Hello World,没有任何延迟。

不用IDE写C#的Hello World的更多相关文章

  1. vc不用IDE编译方法

    一个EXE是如何形成的 比如一个源程序有以下两个文件. 1.c 1.rc 首先cl.exe 会把源代码编译为1.obj rc.exe会把1.rc编译为1.res link.exe会把1.obj 1.r ...

  2. java基础-不用ide如何打包

    java基础-不用ide如何打包 1. 建立目录 src存放源文件 classes存放编译文件 2. 建立类文件 主类 package test.ant; import test.ant.MyTool ...

  3. switch case :在JDK 7中,又加入了对String类型的支持,从此不用再写If-Else来判断字符串了

    switch的case语句可以处理int,short,byte,char类型的值, 因为short,byte,char都会转换成int进行处理,这一点也可以从生成的字节码看出. char a = 'e ...

  4. 传递的值是this,在js里就不用再写$(this)

    <input class="editinput" value="${detail.earlymoneyrmb}" name="earlymone ...

  5. 使用Xcode IDE写node.js

    最近在玩node.js 但是发现很多IDE就是用不顺手 后来发现Xcode可以剖析java script 于是试着使用Xcode来当做node.js的编辑器 首先,在Mac上必须先安装node.js的 ...

  6. 3 不用IDE开发groovy

    1       不用IDE开发groovy 1.1  不用IDE开发的方法 可以在IDE中运行Groovy类或者脚本,但是Groovy也提供了其他运行途径.你能运行Groovy代码基于以下: ·    ...

  7. Delphi使用android的NDK是通过JNI接口,封装好了,不用自己写本地代码,直接调用

    一.Android平台编程方式:      1.基于Android SDK进行开发的第三方应用都必须使用Java语言(Android的SDK基于Java实现)      2.自从ndk r5发布以后, ...

  8. 开箱即用(out-of-box)的Redis序列号生成器,不用再写任何代码,你值得拥有

      先看整体效果 把简单的东西“傻瓜化”是软件开发追求的目标之一.请看下图: 左边是在 application.yml 里配置了3个生成器,右边可以直接注入到代码中使用,注意,不用写任何代码.这酸爽. ...

  9. EF 序列化实体为Json时的循环引用问题(不用自己写实体,不用匿名类型,不用EF的上下文属性)

    自己写实体可以完美解决这个问题.(支持时间格式自定义) 用匿名类型也可以. 设置上下文方法如下: (jz为数据库上下文对象) jz.Configuration.ProxyCreationEnabled ...

随机推荐

  1. BZOJ.4909.[SDOI2017]龙与地下城(正态分布 中心极限定理 FFT Simpson积分)

    BZOJ 洛谷 https://www.luogu.org/blog/ShadowassIIXVIIIIV/solution-p3779# 正态分布 正态分布是随机变量\(X\)的一种概率分布形式.它 ...

  2. [BZOJ2124]等差子序列/[CF452F]Permutation

    [BZOJ2124]等差子序列/[CF452F]Permutation 题目大意: 一个\(1\sim n\)的排列\(A_{1\sim n}\),询问是否存在\(i,j(i<j)\),使得\( ...

  3. [Java]struts2-spring整合时配置监听器

    1.struts2-spring整合时配置监听器 [在web.xml中] <!-- 上下文载入器监听器,确保web服务器启动时,直接完成spring容器的初始化 --/> [Ctrl + ...

  4. 微信支付回调取不到body体中的信息node.js

    因为支付回调返回的数据格式为XML数据格式,需要安装组件body-parser-xml 安装语法:   npm install body-parser-xml --save 在app.js 文件中引入 ...

  5. CentOS 7搭建KVM在线管理面板WebVirtMgr

    系统版本:CentOS 7.4 WebVirtMgr版本:master分支的20180720版本,下载链接(链接:https://pan.baidu.com/s/1kl060hPHDGbwJUR_iM ...

  6. MongoDB中的变更通知

    MongoDb 3.6中引入了一个新特性change stream,简单的来说就是变更通知,它提供了一个接口允许应用实时获取数据库变更,这个在ETL.数据同步.数据迁移.消息通知等方面非常有用. 使用 ...

  7. LPC43xx State Configurable Timer : SCT

  8. An Isolated DAC Using PWM Output

    An Isolated DAC Using PWM Output Arduino‘s (ATmega328P) PWM outputs via analogWrite can be convenien ...

  9. 【Go命令教程】命令汇总

    [Go命令教程]1. 标准命令详解 [Go命令教程]2. go build [Go命令教程]3. go install [Go命令教程]4. go get [Go命令教程]5. go clean [G ...

  10. Modbus TCP和Modbus Rtu协议的区别 转

    http://blog.csdn.net/educast/article/details/9177679   Modbus rtu和Modbus tcp两个协议的本质都是MODBUS协议,都是靠MOD ...