zoukankan      html  css  js  c++  java
  • 再谈C#的装箱和拆箱

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

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

    看下面的一段代码:

    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#代码如下:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    
    namespace boxOrUnbox
    {
        class Program
        {
            static void Main(string[] args)
            {
                //do nothing
            }
    
            static void Box()
            {
                object objValue = 9;
            }
    
            static void Unbox()
            {
                object objValue = 4;
                int value = (int)objValue;
            }
    
            static void LookatArrayList()
            {
                var array = new ArrayList();
                array.Add(1);
                array.Add(2);
    
                foreach (int value in array)
                {
                    Console.WriteLine("value is {0}", value);
                }
            }
    
            static void LookatGenericList()
            {
                var list = new List<int>();
                list.Add(1);
                list.Add(2);
    
                foreach (int value in list)
                {
                    Console.WriteLine("value is {0}", value);
                }
            }
        }
    }
    

    C#的IL代码如下:

    .class private auto ansi beforefieldinit boxOrUnbox.Program
    	extends [mscorlib]System.Object
    {
    	// Methods
    	.method private hidebysig static 
    		void Main (
    			string[] args
    		) cil managed 
    	{
    		// Method begins at RVA 0x2050
    		// Code size 2 (0x2)
    		.maxstack 8
    		.entrypoint
    
    		IL_0000: nop
    		IL_0001: ret
    	} // end of method Program::Main
    
    	.method private hidebysig static 
    		void Box () cil managed 
    	{
    		// Method begins at RVA 0x2054
    		// Code size 10 (0xa)
    		.maxstack 1
    		.locals init (
    			[0] object objValue
    		)
    
    		IL_0000: nop
    		IL_0001: ldc.i4.s 9
    		IL_0003: box [mscorlib]System.Int32
    		IL_0008: stloc.0
    		IL_0009: ret
    	} // end of method Program::Box
    
    	.method private hidebysig static 
    		void Unbox () cil managed 
    	{
    		// Method begins at RVA 0x206c
    		// Code size 16 (0x10)
    		.maxstack 1
    		.locals init (
    			[0] object objValue,
    			[1] int32 'value'
    		)
    
    		IL_0000: nop
    		IL_0001: ldc.i4.4
    		IL_0002: box [mscorlib]System.Int32
    		IL_0007: stloc.0
    		IL_0008: ldloc.0
    		IL_0009: unbox.any [mscorlib]System.Int32
    		IL_000e: stloc.1
    		IL_000f: ret
    	} // end of method Program::Unbox
    
    	.method private hidebysig static 
    		void LookatArrayList () cil managed 
    	{
    		// Method begins at RVA 0x2088
    		// Code size 114 (0x72)
    		.maxstack 2
    		.locals init (
    			[0] class [mscorlib]System.Collections.ArrayList 'array',
    			[1] int32 'value',
    			[2] class [mscorlib]System.Collections.IEnumerator CS$5$0000,
    			[3] bool CS$4$0001,
    			[4] class [mscorlib]System.IDisposable CS$0$0002
    		)
    
    		IL_0000: nop
    		IL_0001: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()
    		IL_0006: stloc.0
    		IL_0007: ldloc.0
    		IL_0008: ldc.i4.1
    		IL_0009: box [mscorlib]System.Int32
    		IL_000e: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
    		IL_0013: pop
    		IL_0014: ldloc.0
    		IL_0015: ldc.i4.2
    		IL_0016: box [mscorlib]System.Int32
    		IL_001b: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
    		IL_0020: pop
    		IL_0021: nop
    		IL_0022: ldloc.0
    		IL_0023: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.ArrayList::GetEnumerator()
    		IL_0028: stloc.2
    		.try
    		{
    			IL_0029: br.s IL_004a
    			// loop start (head: IL_004a)
    				IL_002b: ldloc.2
    				IL_002c: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
    				IL_0031: unbox.any [mscorlib]System.Int32
    				IL_0036: stloc.1
    				IL_0037: nop
    				IL_0038: ldstr "value is {0}"
    				IL_003d: ldloc.1
    				IL_003e: box [mscorlib]System.Int32
    				IL_0043: call void [mscorlib]System.Console::WriteLine(string, object)
    				IL_0048: nop
    				IL_0049: nop
    
    				IL_004a: ldloc.2
    				IL_004b: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
    				IL_0050: stloc.3
    				IL_0051: ldloc.3
    				IL_0052: brtrue.s IL_002b
    			// end loop
    
    			IL_0054: leave.s IL_0070
    		} // end .try
    		finally
    		{
    			IL_0056: ldloc.2
    			IL_0057: isinst [mscorlib]System.IDisposable
    			IL_005c: stloc.s CS$0$0002
    			IL_005e: ldloc.s CS$0$0002
    			IL_0060: ldnull
    			IL_0061: ceq
    			IL_0063: stloc.3
    			IL_0064: ldloc.3
    			IL_0065: brtrue.s IL_006f
    
    			IL_0067: ldloc.s CS$0$0002
    			IL_0069: callvirt instance void [mscorlib]System.IDisposable::Dispose()
    			IL_006e: nop
    
    			IL_006f: endfinally
    		} // end handler
    
    		IL_0070: nop
    		IL_0071: ret
    	} // end of method Program::LookatArrayList
    
    	.method private hidebysig static 
    		void LookatGenericList () cil managed 
    	{
    		// Method begins at RVA 0x2118
    		// Code size 90 (0x5a)
    		.maxstack 2
    		.locals init (
    			[0] class [mscorlib]System.Collections.Generic.List`1<int32> list,
    			[1] int32 'value',
    			[2] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> CS$5$0000,
    			[3] bool CS$4$0001
    		)
    
    		IL_0000: nop
    		IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
    		IL_0006: stloc.0
    		IL_0007: ldloc.0
    		IL_0008: ldc.i4.1
    		IL_0009: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
    		IL_000e: nop
    		IL_000f: ldloc.0
    		IL_0010: ldc.i4.2
    		IL_0011: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
    		IL_0016: nop
    		IL_0017: nop
    		IL_0018: ldloc.0
    		IL_0019: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator()
    		IL_001e: stloc.2
    		.try
    		{
    			IL_001f: br.s IL_003c
    			// loop start (head: IL_003c)
    				IL_0021: ldloca.s CS$5$0000
    				IL_0023: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
    				IL_0028: stloc.1
    				IL_0029: nop
    				IL_002a: ldstr "value is {0}"
    				IL_002f: ldloc.1
    				IL_0030: box [mscorlib]System.Int32
    				IL_0035: call void [mscorlib]System.Console::WriteLine(string, object)
    				IL_003a: nop
    				IL_003b: nop
    
    				IL_003c: ldloca.s CS$5$0000
    				IL_003e: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()
    				IL_0043: stloc.3
    				IL_0044: ldloc.3
    				IL_0045: brtrue.s IL_0021
    			// end loop
    
    			IL_0047: leave.s IL_0058
    		} // end .try
    		finally
    		{
    			IL_0049: ldloca.s CS$5$0000
    			IL_004b: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>
    			IL_0051: callvirt instance void [mscorlib]System.IDisposable::Dispose()
    			IL_0056: nop
    			IL_0057: endfinally
    		} // end handler
    
    		IL_0058: nop
    		IL_0059: ret
    	} // end of method Program::LookatGenericList
    
    	.method public hidebysig specialname rtspecialname 
    		instance void .ctor () cil managed 
    	{
    		// Method begins at RVA 0x2190
    		// Code size 7 (0x7)
    		.maxstack 8
    
    		IL_0000: ldarg.0
    		IL_0001: call instance void [mscorlib]System.Object::.ctor()
    		IL_0006: ret
    	} // end of method Program::.ctor
    
    } // end of class boxOrUnbox.Program
    

      

  • 相关阅读:
    基于Python的人脸动漫转换
    let 与 var的区别
    【LeetCode】汇总
    【HDU】4632 Palindrome subsequence(回文子串的个数)
    【算法】均匀的生成圆内的随机点
    【LeetCode】725. Split Linked List in Parts
    【LeetCode】445. Add Two Numbers II
    【LeetCode】437. Path Sum III
    【LeetCode】222. Count Complete Tree Nodes
    【LeetCode】124. Binary Tree Maximum Path Sum
  • 原文地址:https://www.cnblogs.com/yukaizhao/p/csharp_box_unbox_2.html
Copyright © 2011-2022 走看看