zoukankan      html  css  js  c++  java
  • 初读 c# IL中间语言

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

     1         static StringBuilder sb = new StringBuilder();
     2 
     3         static int filecount = 0;
     4         static int dirCount = 0;
     5 
     6         /// <summary>  
     7         /// 获取目录path下所有子文件名  
     8         /// </summary>  
     9         public static List<string> getAllFiles(String path, int depth = 0)
    10         {
    11             List<string> strs = new List<string>();
    12             if (System.IO.Directory.Exists(path))
    13             {
    14                 //所有子文件名  
    15                 string[] files = System.IO.Directory.GetFiles(path);
    16                 foreach (string file in files)
    17                 {
    18                     sb.Append(new string('*', depth * 3) + file + "
    ");
    19                     strs.Add(file);
    20                     filecount++;
    21                 }
    22                 //所有子目录名  
    23                 string[] Dirs = System.IO.Directory.GetDirectories(path);
    24                 foreach (string dir in Dirs)
    25                 {
    26                     dirCount++;
    27                     sb.Append(new string('*', depth * 3) + dir + "
    ");
    28                     var tmp = getAllFiles(dir, depth + 1);  //子目录下所有子文件名  
    29                     if (!tmp.Equals(""))
    30                     {
    31                         strs.AddRange(tmp);
    32                     }
    33                 }
    34             }
    35             return strs;
    36         }

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

    .method public hidebysig static class [mscorlib]System.Collections.Generic.List`1<string> 
            getAllFiles(string path,
                        [opt] int32 depth) cil managed
    {
      .param [2] = int32(0x00000000)
      // 代码大小       262 (0x106)
      .maxstack  4
      .locals init ([0] class [mscorlib]System.Collections.Generic.List`1<string> strs,
               [1] string[] files,
               [2] string file,
               [3] string[] Dirs,
               [4] string dir,
               [5] class [mscorlib]System.Collections.Generic.List`1<string> tmp,
               [6] class [mscorlib]System.Collections.Generic.List`1<string> CS$1$0000,
               [7] bool CS$4$0001,
               [8] string[] CS$6$0002,
               [9] int32 CS$7$0003)          // 带$符号的变量是编译器定义的临时变量
      IL_0000:  nop
      IL_0001:  newobj     instance void class [mscorlib]System.Collections.Generic.List`1<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$4$0001   //把 call的结果和0作比较,把比较的结果存到这个变量中
      IL_0012:  ldloc.s    CS$4$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$6$0002    //把这个变量的值存到002变量中
      IL_0025:  ldc.i4.0                
      IL_0026:  stloc.s    CS$7$0003    //把0存储到003的变量中
      IL_0028:  br.s       IL_006c       //跳转到006c行
      IL_002a:  ldloc.s    CS$6$0002      //加载数组
      IL_002c:  ldloc.s    CS$7$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.2
      IL_0041:  ldstr      "
    "
      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`1<string>::Add(!0)
      IL_0058:  nop
      IL_0059:  ldsfld     int32 Client.Program::filecount
      IL_005e:  ldc.i4.1
      IL_005f:  add           //filecount加1
      IL_0060:  stsfld     int32 Client.Program::filecount
      IL_0065:  nop
      IL_0066:  ldloc.s    CS$7$0003   加载了003,值为0
      IL_0068:  ldc.i4.1
      IL_0069:  add
      IL_006a:  stloc.s    CS$7$0003   给003加了1,此时003的值为1,这么看来003就是个计数器,用来控制循环
      IL_006c:  ldloc.s    CS$7$0003         //加载003,第一次,变量中为0
      IL_006e:  ldloc.s    CS$6$0002         //加载002,此时为files数组
      IL_0070:  ldlen                        //取数组长度,并转为int类型
      IL_0071:  conv.i4
      IL_0072:  clt
      IL_0074:  stloc.s    CS$4$0001          //看003是否比数组长度小,把比较结果存到001中
      IL_0076:  ldloc.s    CS$4$0001
      IL_0078:  brtrue.s   IL_002a            //如果为true,跳转到002a行
      IL_007a:  ldarg.0
      IL_007b:  call       string[] [mscorlib]System.IO.Directory::GetDirectories(string)
      IL_0080:  stloc.3
      IL_0081:  nop
      IL_0082:  ldloc.3
      IL_0083:  stloc.s    CS$6$0002
      IL_0085:  ldc.i4.0
      IL_0086:  stloc.s    CS$7$0003
      IL_0088:  br.s       IL_00ef
      IL_008a:  ldloc.s    CS$6$0002
      IL_008c:  ldloc.s    CS$7$0003
      IL_008e:  ldelem.ref
      IL_008f:  stloc.s    dir
      IL_0091:  nop
      IL_0092:  ldsfld     int32 Client.Program::dirCount
      IL_0097:  ldc.i4.1
      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   42
      IL_00a5:  ldarg.1
      IL_00a6:  ldc.i4.3
      IL_00a7:  mul
      IL_00a8:  newobj     instance void [mscorlib]System.String::.ctor(char,
                                                                        int32)
      IL_00ad:  ldloc.s    dir
      IL_00af:  ldstr      "
    "
      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.1
      IL_00c2:  ldc.i4.1
      IL_00c3:  add
      IL_00c4:  call       class [mscorlib]System.Collections.Generic.List`1<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$4$0001
      IL_00d9:  ldloc.s    CS$4$0001
      IL_00db:  brtrue.s   IL_00e8
      IL_00dd:  nop
      IL_00de:  ldloc.0
      IL_00df:  ldloc.s    tmp
      IL_00e1:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<string>::AddRange(class [mscorlib]System.Collections.Generic.IEnumerable`1<!0>)
      IL_00e6:  nop
      IL_00e7:  nop
      IL_00e8:  nop
      IL_00e9:  ldloc.s    CS$7$0003
      IL_00eb:  ldc.i4.1
      IL_00ec:  add
      IL_00ed:  stloc.s    CS$7$0003
      IL_00ef:  ldloc.s    CS$7$0003
      IL_00f1:  ldloc.s    CS$6$0002
      IL_00f3:  ldlen
      IL_00f4:  conv.i4
      IL_00f5:  clt
      IL_00f7:  stloc.s    CS$4$0001
      IL_00f9:  ldloc.s    CS$4$0001
      IL_00fb:  brtrue.s   IL_008a
      IL_00fd:  nop
      IL_00fe:  ldloc.0
      IL_00ff:  stloc.s    CS$1$0000
      IL_0101:  br.s       IL_0103
      IL_0103:  ldloc.s    CS$1$0000
      IL_0105:  ret
    } // end of method Program::getAllFiles

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

  • 相关阅读:
    无法在WEB服务器上启动调试
    Zedgraph悬停时显示内容闪烁的解决
    用ZedGraph控件作图圆
    34.node.js之Url & QueryString模块
    33.Node.js 文件系统fs
    32.Node.js中的常用工具类util
    31.Node.js 常用工具 util
    30.Node.js 全局对象
    28.Node.js 函数和匿名函数
    27.Node.js模块系统
  • 原文地址:https://www.cnblogs.com/wangqiang3311/p/7988775.html
Copyright © 2011-2022 走看看