对一段c#编写的代码,有一些疑问,想通过IL中间语言看看,编译后是怎么处理的。代码如下:

         static StringBuilder sb = new StringBuilder();

         static int filecount = ;
static int dirCount = ; /// <summary>
/// 获取目录path下所有子文件名
/// </summary>
public static List<string> getAllFiles(String path, int depth = )
{
List<string> strs = new List<string>();
if (System.IO.Directory.Exists(path))
{
//所有子文件名
string[] files = System.IO.Directory.GetFiles(path);
foreach (string file in files)
{
sb.Append(new string('*', depth * ) + file + "\r\n");
strs.Add(file);
filecount++;
}
//所有子目录名
string[] Dirs = System.IO.Directory.GetDirectories(path);
foreach (string dir in Dirs)
{
dirCount++;
sb.Append(new string('*', depth * ) + dir + "\r\n");
var tmp = getAllFiles(dir, depth + ); //子目录下所有子文件名
if (!tmp.Equals(""))
{
strs.AddRange(tmp);
}
}
}
return strs;
}

这段代码的功能是很简单的:给定一个文件夹,返回下面的所有文件(递归遍历)。我的疑问:在第11行,递归调用的时候,strs变量(用来存放所有文件的名称列表)能够保存到所有文件名吗?程序运行的结果告诉我,代码没有任何问题。代码是别人写的,如果是我写的话,可能会在方法之外定义一个变量,在递归的时候,遇到文件的时候,把名字里存进去,而递归方法就不用返回值。当然按照依赖关系来看的话,方法内部用的变量,要么是内部自定义的,要么是参数传进来的,这样对外没有依赖,方法的复用性高。毋庸置疑,代码没啥问题。第一行的sb是我加进去的。通过查看IL代码,明白了一些道理,看到了编译器为我们程序处理的一些东西,比较感兴趣,就把这段IL摘下来:

.method public hidebysig static class [mscorlib]System.Collections.Generic.List`<string>
getAllFiles(string path,
[opt] int32 depth) cil managed
{
.param [] = int32(0x00000000)
// 代码大小 262 (0x106)
.maxstack
.locals init ([] class [mscorlib]System.Collections.Generic.List`<string> strs,
[] string[] files,
[] string file,
[] string[] Dirs,
[] string dir,
[] class [mscorlib]System.Collections.Generic.List`<string> tmp,
[] class [mscorlib]System.Collections.Generic.List`<string> CS$$,
[] bool CS$$,
[] string[] CS$$,
[] int32 CS$$) // 带$符号的变量是编译器定义的临时变量
IL_0000: nop
IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`<string>::.ctor()
IL_0006: stloc.0 //把上面实例化好的对象保存到第一个变量中,也就是strs
IL_0007: ldarg.0 //加载第一个参数,也就是path
IL_0008: call bool [mscorlib]System.IO.Directory::Exists(string)
IL_000d: ldc.i4.0 //在堆栈中加载一个int类型,值为0的常量
IL_000e: ceq
IL_0010: stloc.s CS$$0001 //把 call的结果和0作比较,把比较的结果存到这个变量中
IL_0012: ldloc.s CS$$0001 //加载这个变量到堆栈中
IL_0014: brtrue IL_00fe //如果call的结果和0相等就跳转了,也就是说001中存了true
IL_0019: nop
IL_001a: ldarg.0
IL_001b: call string[] [mscorlib]System.IO.Directory::GetFiles(string)
IL_0020: stloc.1 //存储到第一个变量:files
IL_0021: nop
IL_0022: ldloc.1 //加载到第一个变量到堆栈里
IL_0023: stloc.s CS$$0002 //把这个变量的值存到002变量中
IL_0025: ldc.i4.0
IL_0026: stloc.s CS$$0003 //把0存储到003的变量中
IL_0028: br.s IL_006c //跳转到006c行
IL_002a: ldloc.s CS$$0002 //加载数组
IL_002c: ldloc.s CS$$0003 //加载003,此时值为0
IL_002e: ldelem.ref //取数组中的一个元素
IL_002f: stloc.2 //存到变量2 file中
IL_0030: nop
IL_0031: ldsfld class [mscorlib]System.Text.StringBuilder Client.Program::sb //加载sb字段
IL_0036: ldc.i4.s 42 //加载常量42
IL_0038: ldarg.1 //加载第二个参数depth
IL_0039: ldc.i4.3 //加载常量3
IL_003a: mul //3*depth 乘法
IL_003b: newobj instance void [mscorlib]System.String::.ctor(char,
int32)
IL_0040: ldloc.
IL_0041: ldstr "\r\n"
IL_0046: call string [mscorlib]System.String::Concat(string,
string,
string) //实例化了string的实例,并把前面3个字符串给拼接起来
IL_004b: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
IL_0050: pop
IL_0051: ldloc.0 //加载第一个变量strs
IL_0052: ldloc.2 //加载第三个变量file
IL_0053: callvirt instance void class [mscorlib]System.Collections.Generic.List`<string>::Add(!)
IL_0058: nop
IL_0059: ldsfld int32 Client.Program::filecount
IL_005e: ldc.i4.
IL_005f: add //filecount加1
IL_0060: stsfld int32 Client.Program::filecount
IL_0065: nop
IL_0066: ldloc.s CS$$0003 加载了003,值为0
IL_0068: ldc.i4.
IL_0069: add
IL_006a: stloc.s CS$$0003 给003加了1,此时003的值为1,这么看来003就是个计数器,用来控制循环
IL_006c: ldloc.s CS$$0003 //加载003,第一次,变量中为0
IL_006e: ldloc.s CS$$0002 //加载002,此时为files数组
IL_0070: ldlen //取数组长度,并转为int类型
IL_0071: conv.i4
IL_0072: clt
IL_0074: stloc.s CS$$0001 //看003是否比数组长度小,把比较结果存到001中
IL_0076: ldloc.s CS$$
IL_0078: brtrue.s IL_002a //如果为true,跳转到002a行
IL_007a: ldarg.
IL_007b: call string[] [mscorlib]System.IO.Directory::GetDirectories(string)
IL_0080: stloc.
IL_0081: nop
IL_0082: ldloc.
IL_0083: stloc.s CS$$
IL_0085: ldc.i4.
IL_0086: stloc.s CS$$
IL_0088: br.s IL_00ef
IL_008a: ldloc.s CS$$
IL_008c: ldloc.s CS$$
IL_008e: ldelem.ref
IL_008f: stloc.s dir
IL_0091: nop
IL_0092: ldsfld int32 Client.Program::dirCount
IL_0097: ldc.i4.
IL_0098: add
IL_0099: stsfld int32 Client.Program::dirCount
IL_009e: ldsfld class [mscorlib]System.Text.StringBuilder Client.Program::sb
IL_00a3: ldc.i4.s
IL_00a5: ldarg.
IL_00a6: ldc.i4.
IL_00a7: mul
IL_00a8: newobj instance void [mscorlib]System.String::.ctor(char,
int32)
IL_00ad: ldloc.s dir
IL_00af: ldstr "\r\n"
IL_00b4: call string [mscorlib]System.String::Concat(string,
string,
string)
IL_00b9: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
IL_00be: pop
IL_00bf: ldloc.s dir
IL_00c1: ldarg.
IL_00c2: ldc.i4.
IL_00c3: add
IL_00c4: call class [mscorlib]System.Collections.Generic.List`<string> Client.Program::getAllFiles(string,
int32)
IL_00c9: stloc.s tmp
IL_00cb: ldloc.s tmp
IL_00cd: ldstr ""
IL_00d2: callvirt instance bool [mscorlib]System.Object::Equals(object)
IL_00d7: stloc.s CS$$
IL_00d9: ldloc.s CS$$
IL_00db: brtrue.s IL_00e8
IL_00dd: nop
IL_00de: ldloc.
IL_00df: ldloc.s tmp
IL_00e1: callvirt instance void class [mscorlib]System.Collections.Generic.List`<string>::AddRange(class [mscorlib]System.Collections.Generic.IEnumerable`<!>)
IL_00e6: nop
IL_00e7: nop
IL_00e8: nop
IL_00e9: ldloc.s CS$$
IL_00eb: ldc.i4.
IL_00ec: add
IL_00ed: stloc.s CS$$
IL_00ef: ldloc.s CS$$
IL_00f1: ldloc.s CS$$
IL_00f3: ldlen
IL_00f4: conv.i4
IL_00f5: clt
IL_00f7: stloc.s CS$$
IL_00f9: ldloc.s CS$$
IL_00fb: brtrue.s IL_008a
IL_00fd: nop
IL_00fe: ldloc.
IL_00ff: stloc.s CS$$
IL_0101: br.s IL_0103
IL_0103: ldloc.s CS$$
IL_0105: ret
} // end of method Program::getAllFiles

我加注释的地方,就是方法从头开始到第一个循环结束的地方,后面的循环和这个类似,就不解读了。

初读 c# IL中间语言的更多相关文章

  1. 读懂IL代码就这么简单(三)完结篇

    一 前言 写了两篇关于IL指令相关的文章,分别把值类型与引用类型在 堆与栈上的操作区别详细的写了一遍 这第三篇也是最后一篇,之所以到第三篇就结束了,是因为以我现在的层次,能理解到的都写完了,而且个人认 ...

  2. 读懂IL代码就这么简单 (一)

    一前言 感谢 @冰麟轻武 指出文章的错误之处,现已更正 对于IL代码没了解之前总感觉很神奇,初一看完全不知所云,只听高手们说,了解IL代码你能更加清楚的知道你的代码是如何运行相互调用的,此言一出不明觉 ...

  3. 读懂IL代码就这么简单

    原文地址:http://www.cnblogs.com/zery/p/3366175.html 一前言 感谢 @冰麟轻武 指出文章的错误之处,现已更正 对于IL代码没了解之前总感觉很神奇,初一看完全不 ...

  4. 【转载】读懂IL代码就这么简单(三)完结篇

    一 前言 写了两篇关于IL指令相关的文章,分别把值类型与引用类型在 堆与栈上的操作区别详细的写了一遍这第三篇也是最后一篇,之所以到第三篇就结束了,是因为以我现在的层次,能理解到的都写完了,而且个人认为 ...

  5. 【转载】读懂IL代码就这么简单 (一)

    一前言 感谢 @冰麟轻武 指出文章的错误之处,现已更正 对于IL代码没了解之前总感觉很神奇,初一看完全不知所云,只听高手们说,了解IL代码你能更加清楚的知道你的代码是如何运行相互调用的,此言一出不明觉 ...

  6. 读懂IL代码就这么简单(二)

    一 前言 IL系列 第一篇写完后 得到高人指点,及时更正了文章中的错误,也使得我写这篇文章时更加谨慎,自己在了解相关知识点时,也更为细致.个人觉得既然做为文章写出来,就一定要保证比较高的质量,和正确率 ...

  7. 读懂IL

    读懂IL 先说说学IL有什么用,有人可能觉得这玩意平常写代码又用不上,学了有个卵用.到底有没有卵用呢,暂且也不说什么学了可以看看一些语法糖的实现,或对.net理解更深一点这些虚头巴脑的东西.最重要的理 ...

  8. 轻松读懂IL

    轻松读懂IL先说说学IL有什么用,有人可能觉得这玩意平常写代码又用不上,学了有个卵用.到底有没有卵用呢,暂且也不说什么学了可以看看一些语法糖的实现,或对.net理解更深一点这些虚头巴脑的东西.最重要的 ...

  9. 读懂IL代码就这么简单 ---- IL系列文章

    读懂IL代码就这么简单 (一) 读懂IL代码就这么简单(二) 读懂IL代码就这么简单(三)完结篇 出处:http://www.cnblogs.com/zery/tag/IL%20%E7%B3%BB%E ...

随机推荐

  1. ubuntu:通过封装验证码类库一步步安装php的gd扩展

    我相信很多人的lamp环境都是直接复制一堆参数安装进去的,这里有可能成功,也有可能失败,如果是新手,估计要碰到各种错误,就算安装成功,也未必知道那些参数是干嘛的,反正装进去能用就行. 我当初开始的时候 ...

  2. 一位IT男的7年工作经验总结

    一位IT男的7年工作经验总结 1.分享第一条经验:"学历代表过去.能力代表现在.学习力代表未来." 其实这是一个来自国外教育领域的一个研究结果.相信工作过几年.十几年的朋友对这个道 ...

  3. web自动化一(selenium+python+pycharm环境搭建)

    年前公司刚刚搭起了web自动化测试框架的环境,趁着过完年还没全部忘掉,准备把如何搭建环境的方法和大家分享下,有哪里不对的地方,请批评指正,共同进步,共勉! 为此我把搭建环境所需的软件打包上传到百度云, ...

  4. CentOS 6安装Oracle报错解决方案

    1. Preparing to launch Oracle Universal Installer from /tmp/OraInstall2017-05-23_04-18-48AM. Please ...

  5. 在web工程中设置首页的页面

    有些时候删除了系统自带的index.jsp删除后会出现如下图错误 解决办法,新创建一个以你自己命名的jsp文件,然后在对该web工程的WEB-INF 目录下的web.xml进行添加加上下面的注释所带的 ...

  6. Day5模块-shutil模块

    参考博客:http://www.cnblogs.com/wupeiqi/articles/4963027.html shutil模块是高级的文件.文件夹.压缩处理的模块.比如文件的copy.压缩等. ...

  7. 网络基础Cisco路由交换三

    热备份路由协议HSRP:Cisco私有协议 确保了当网络边缘设备或接入链路出现故障时,用户通信能迅速并透明地恢复,以此为ip网络提供余性,通过使用同意虚拟ip地址和虚拟mac地址,LAN网段上的两台或 ...

  8. 关于我上传的activiti自定义流程demo的说明

    最近又收到了一些询问activiti的问题,其中好几个都是向我索要我上传的这个activiti自定义流程demo的数据库设计. 索要的多了,而我早就把这个库给删掉了,所以我便觉得有必要做一个说明: 我 ...

  9. json_encode处理json数据中文乱码

    今天使用json_encode 把一个数组转换成json数据,echo处理的时候,显示为null.去查了php手册. 该函数只能接受 UTF-8 编码的数据. 在网上搜了下,找到了解决方法. < ...

  10. PHP XML简介

    php xml文件编程. xml简介 XML作用 1.可以作为程序间通讯的标准(ajax text xml) 2.可以作为配置文件 3.可以作为小型数据库 XML语法 一个xml文件应该包括以下几个内 ...