• 深入理解C#的装箱和拆箱(二)


    上一篇写了一下装箱拆箱的定义和IL分析,这一篇我们看下使用泛型和不使用泛型引发装箱拆箱的情况

    1.使用非泛型集合时引发的装箱和拆箱操作 

    看下面的一段代码:

    1
    2
    3
    4
    5
    6
    7
    8
    var array = new ArrayList();
    array.Add(1);
    array.Add(2);
     
    foreach (int value in array)
    {
    Console.WriteLine(“value is {0}”,value);
    }

    代码声明了一个ArrayList对象,向ArrayList中添加两个数字1,2;然后使用foreach将ArrayList中的元素打印到控制台。

    在这个过程中会发生两次装箱操作和两次拆箱操作,在向ArrayList中添加int类型元素时会发生装箱,在使用foreach枚举ArrayList中的int类型元素时会发生拆箱操作,将object类型转换成int类型,在执行到Console.WriteLine时,还会执行两次的装箱操作;这一段代码执行了6次的装箱和拆箱操作;如果ArrayList的元素个数很多,执行装箱拆箱的操作会更多。

    你可以通过使用ILSpy之类的工具查看IL代码的box,unbox指令查看装箱和拆箱的过程

    2.使用泛型集合的情况

    请看如下代码:

    var list = new List<int>();
    list.Add(1);
    list.Add(2);
     
    foreach (int value in list)
    {
    Console.WriteLine("value is {0}", value);
    }

    代码和1中的代码的差别在于集合的类型使用了泛型的List,而非ArrayList;我们同样可以通过查看IL代码查看装箱拆箱的情况,上述代码只会在Console.WriteLine()方法时执行2次装箱操作,不需要拆箱操作。

    可以看出泛型可以避免装箱拆箱带来的不必要的性能消耗;当然泛型的好处不止于此,泛型还可以增加程序的可读性,使程序更容易被复用等等。

    本文使用的C#代码如下:

     1 using System;
     2 using System.Collections;
     3 using System.Collections.Generic;
     4  
     5 namespace boxOrUnbox
     6 {
     7     class Program
     8     {
     9         static void Main(string[] args)
    10         {
    11             //do nothing
    12         }
    13  
    14         static void Box()
    15         {
    16             object objValue = 9;
    17         }
    18  
    19         static void Unbox()
    20         {
    21             object objValue = 4;
    22             int value = (int)objValue;
    23         }
    24  
    25         static void LookatArrayList()
    26         {
    27             var array = new ArrayList();
    28             array.Add(1);
    29             array.Add(2);
    30  
    31             foreach (int value in array)
    32             {
    33                 Console.WriteLine("value is {0}", value);
    34             }
    35         }
    36  
    37         static void LookatGenericList()
    38         {
    39             var list = new List<int>();
    40             list.Add(1);
    41             list.Add(2);
    42  
    43             foreach (int value in list)
    44             {
    45                 Console.WriteLine("value is {0}", value);
    46             }
    47         }
    48     }
    49 }

    C#的IL代码如下:

      1 .class private auto ansi beforefieldinit boxOrUnbox.Program
      2     extends [mscorlib]System.Object
      3 {
      4     // Methods
      5     .method private hidebysig static
      6         void Main (
      7             string[] args
      8         ) cil managed
      9     {
     10         // Method begins at RVA 0x2050
     11         // Code size 2 (0x2)
     12         .maxstack 8
     13         .entrypoint
     14  
     15         IL_0000: nop
     16         IL_0001: ret
     17     } // end of method Program::Main
     18  
     19     .method private hidebysig static
     20         void Box () cil managed
     21     {
     22         // Method begins at RVA 0x2054
     23         // Code size 10 (0xa)
     24         .maxstack 1
     25         .locals init (
     26             [0] object objValue
     27         )
     28  
     29         IL_0000: nop
     30         IL_0001: ldc.i4.s 9
     31         IL_0003: box [mscorlib]System.Int32
     32         IL_0008: stloc.0
     33         IL_0009: ret
     34     } // end of method Program::Box
     35  
     36     .method private hidebysig static
     37         void Unbox () cil managed
     38     {
     39         // Method begins at RVA 0x206c
     40         // Code size 16 (0x10)
     41         .maxstack 1
     42         .locals init (
     43             [0] object objValue,
     44             [1] int32 'value'
     45         )
     46  
     47         IL_0000: nop
     48         IL_0001: ldc.i4.4
     49         IL_0002: box [mscorlib]System.Int32
     50         IL_0007: stloc.0
     51         IL_0008: ldloc.0
     52         IL_0009: unbox.any [mscorlib]System.Int32
     53         IL_000e: stloc.1
     54         IL_000f: ret
     55     } // end of method Program::Unbox
     56  
     57     .method private hidebysig static
     58         void LookatArrayList () cil managed
     59     {
     60         // Method begins at RVA 0x2088
     61         // Code size 114 (0x72)
     62         .maxstack 2
     63         .locals init (
     64             [0] class [mscorlib]System.Collections.ArrayList 'array',
     65             [1] int32 'value',
     66             [2] class [mscorlib]System.Collections.IEnumerator CS$5$0000,
     67             [3] bool CS$4$0001,
     68             [4] class [mscorlib]System.IDisposable CS$0$0002
     69         )
     70  
     71         IL_0000: nop
     72         IL_0001: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()
     73         IL_0006: stloc.0
     74         IL_0007: ldloc.0
     75         IL_0008: ldc.i4.1
     76         IL_0009: box [mscorlib]System.Int32
     77         IL_000e: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
     78         IL_0013: pop
     79         IL_0014: ldloc.0
     80         IL_0015: ldc.i4.2
     81         IL_0016: box [mscorlib]System.Int32
     82         IL_001b: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
     83         IL_0020: pop
     84         IL_0021: nop
     85         IL_0022: ldloc.0
     86         IL_0023: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.ArrayList::GetEnumerator()
     87         IL_0028: stloc.2
     88         .try
     89         {
     90             IL_0029: br.s IL_004a
     91             // loop start (head: IL_004a)
     92                 IL_002b: ldloc.2
     93                 IL_002c: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
     94                 IL_0031: unbox.any [mscorlib]System.Int32
     95                 IL_0036: stloc.1
     96                 IL_0037: nop
     97                 IL_0038: ldstr "value is {0}"
     98                 IL_003d: ldloc.1
     99                 IL_003e: box [mscorlib]System.Int32
    100                 IL_0043: call void [mscorlib]System.Console::WriteLine(string, object)
    101                 IL_0048: nop
    102                 IL_0049: nop
    103  
    104                 IL_004a: ldloc.2
    105                 IL_004b: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
    106                 IL_0050: stloc.3
    107                 IL_0051: ldloc.3
    108                 IL_0052: brtrue.s IL_002b
    109             // end loop
    110  
    111             IL_0054: leave.s IL_0070
    112         } // end .try
    113         finally
    114         {
    115             IL_0056: ldloc.2
    116             IL_0057: isinst [mscorlib]System.IDisposable
    117             IL_005c: stloc.s CS$0$0002
    118             IL_005e: ldloc.s CS$0$0002
    119             IL_0060: ldnull
    120             IL_0061: ceq
    121             IL_0063: stloc.3
    122             IL_0064: ldloc.3
    123             IL_0065: brtrue.s IL_006f
    124  
    125             IL_0067: ldloc.s CS$0$0002
    126             IL_0069: callvirt instance void [mscorlib]System.IDisposable::Dispose()
    127             IL_006e: nop
    128  
    129             IL_006f: endfinally
    130         } // end handler
    131  
    132         IL_0070: nop
    133         IL_0071: ret
    134     } // end of method Program::LookatArrayList
    135  
    136     .method private hidebysig static
    137         void LookatGenericList () cil managed
    138     {
    139         // Method begins at RVA 0x2118
    140         // Code size 90 (0x5a)
    141         .maxstack 2
    142         .locals init (
    143             [0] class [mscorlib]System.Collections.Generic.List`1<int32> list,
    144             [1] int32 'value',
    145             [2] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> CS$5$0000,
    146             [3] bool CS$4$0001
    147         )
    148  
    149         IL_0000: nop
    150         IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
    151         IL_0006: stloc.0
    152         IL_0007: ldloc.0
    153         IL_0008: ldc.i4.1
    154         IL_0009: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
    155         IL_000e: nop
    156         IL_000f: ldloc.0
    157         IL_0010: ldc.i4.2
    158         IL_0011: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
    159         IL_0016: nop
    160         IL_0017: nop
    161         IL_0018: ldloc.0
    162         IL_0019: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator()
    163         IL_001e: stloc.2
    164         .try
    165         {
    166             IL_001f: br.s IL_003c
    167             // loop start (head: IL_003c)
    168                 IL_0021: ldloca.s CS$5$0000
    169                 IL_0023: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
    170                 IL_0028: stloc.1
    171                 IL_0029: nop
    172                 IL_002a: ldstr "value is {0}"
    173                 IL_002f: ldloc.1
    174                 IL_0030: box [mscorlib]System.Int32
    175                 IL_0035: call void [mscorlib]System.Console::WriteLine(string, object)
    176                 IL_003a: nop
    177                 IL_003b: nop
    178  
    179                 IL_003c: ldloca.s CS$5$0000
    180                 IL_003e: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()
    181                 IL_0043: stloc.3
    182                 IL_0044: ldloc.3
    183                 IL_0045: brtrue.s IL_0021
    184             // end loop
    185  
    186             IL_0047: leave.s IL_0058
    187         } // end .try
    188         finally
    189         {
    190             IL_0049: ldloca.s CS$5$0000
    191             IL_004b: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>
    192             IL_0051: callvirt instance void [mscorlib]System.IDisposable::Dispose()
    193             IL_0056: nop
    194             IL_0057: endfinally
    195         } // end handler
    196  
    197         IL_0058: nop
    198         IL_0059: ret
    199     } // end of method Program::LookatGenericList
    200  
    201     .method public hidebysig specialname rtspecialname
    202         instance void .ctor () cil managed
    203     {
    204         // Method begins at RVA 0x2190
    205         // Code size 7 (0x7)
    206         .maxstack 8
    207  
    208         IL_0000: ldarg.0
    209         IL_0001: call instance void [mscorlib]System.Object::.ctor()
    210         IL_0006: ret
    211     } // end of method Program::.ctor
    212  
    213 } // end of class boxOrUnbox.Program

    ***********转摘:https://www.cnblogs.com/yukaizhao/archive/2004/01/13/csharp_box_unbox_2.html

  • 相关阅读:
    Sphinx 自动化文档
    手把手教你用Rancher创建产品质量数据库设置
    手把手教你用Rancher创建产品质量数据库设置
    手把手教你用Rancher创建产品质量数据库设置
    九、新人成才之路《成才大原则 谈人生大规划》
    九、新人成才之路《成才大原则 谈人生大规划》
    九、新人成才之路《成才大原则 谈人生大规划》
    九、新人成才之路《成才大原则 谈人生大规划》
    Linux常用命令大全(非常全!!!)
    Linux常用命令大全(非常全!!!)
  • 原文地址:https://www.cnblogs.com/linybo/p/13679627.html
Copyright © 2020-2023  润新知