C# 基础之装拆箱 IL 层

C# 基础之装拆箱

装箱:当一个值类型转成引用类型,我们可以看成 我们把 1元钱装入钱包中,此时发生装箱操作。

拆箱:当一个引用类型转成值类型,我们可以看成 从钱包中把 1元钱 提取出来。

以上个人通俗白话的理解。

测试案例:
在这里插入图片描述
这里我声明了一个引用类型和值类型。

在这里插入图片描述

上面是发生装拆箱的代码,很容易看清楚之间的类型转换后的装拆箱,不过我们从底层IL语言来看。

我们先看看装箱操作做了什么事情。

在这里插入图片描述
我们可以看的 IL 先入栈,之后发生装箱的操作,之后把计算堆栈的推送给静态字段(赋值)

再看看拆箱操作的IL。

在这里插入图片描述
IL 基本一样除了中间的 unbox il指令不一样以外。

那么该如何避免装拆箱?答案:泛型

        static int i = 1;
        static object i2 = new object();
        static void Main(string[] args)
        {
            Box<int>(i);

            BoxRef<object>(i2);
        }

        //值类型转成引用类型 装箱
        static void Box<T1>(T1 it) where T1 : struct
        {
            T1 ol;
            ol = it;
        }

        static void BoxRef<T1>(T1 it) where T1 : class
        {
            T1 ol;
            ol = it;
        }

上述代码拆分值类型与引用类型的泛型(String 特殊)

接着我们看看IL代码

// Token: 0x02000002 RID: 2
.class public auto ansi beforefieldinit ClassLibrary6.Class1
	extends [mscorlib]System.Object
{
	// Fields
	// Token: 0x04000001 RID: 1
	.field private static int32 i
	// Token: 0x04000002 RID: 2
	.field private static object i2

	// Methods
	// Token: 0x06000001 RID: 1 RVA: 0x00002050 File Offset: 0x00000250
	.method private hidebysig static 
		void Main (
			string[] args
		) cil managed 
	{
		// Header Size: 1 byte
		// Code Size: 24 (0x18) bytes
		.maxstack 8

		/* (16,9)-(16,10) C:\Users\admin\source\repos\ClassLibrary6\ClassLibrary6\Class1.cs */
		/* 0x00000251 00           */ IL_0000: nop
		/* (17,13)-(17,25) C:\Users\admin\source\repos\ClassLibrary6\ClassLibrary6\Class1.cs */
		/* 0x00000252 7E01000004   */ IL_0001: ldsfld    int32 ClassLibrary6.Class1::i
		/* 0x00000257 280100002B   */ IL_0006: call      void ClassLibrary6.Class1::Box<int32>(!!0)
		/* 0x0000025C 00           */ IL_000B: nop
		/* (19,13)-(19,32) C:\Users\admin\source\repos\ClassLibrary6\ClassLibrary6\Class1.cs */
		/* 0x0000025D 7E02000004   */ IL_000C: ldsfld    object ClassLibrary6.Class1::i2
		/* 0x00000262 280200002B   */ IL_0011: call      void ClassLibrary6.Class1::BoxRef<object>(!!0)
		/* 0x00000267 00           */ IL_0016: nop
		/* (20,9)-(20,10) C:\Users\admin\source\repos\ClassLibrary6\ClassLibrary6\Class1.cs */
		/* 0x00000268 2A           */ IL_0017: ret
	} // end of method Class1::Main

	// Token: 0x06000002 RID: 2 RVA: 0x0000206C File Offset: 0x0000026C
	.method private hidebysig static 
		void Box<valuetype .ctor ([mscorlib]System.ValueType) T1> (
			!!T1 it
		) cil managed 
	{
		// Header Size: 12 bytes
		// Code Size: 4 (0x4) bytes
		// LocalVarSig Token: 0x11000001 RID: 1
		.maxstack 1
		.locals init (
			[0] !!T1 ol
		)

		/* (24,9)-(24,10) C:\Users\admin\source\repos\ClassLibrary6\ClassLibrary6\Class1.cs */
		/* 0x00000278 00           */ IL_0000: nop
		/* (26,13)-(26,21) C:\Users\admin\source\repos\ClassLibrary6\ClassLibrary6\Class1.cs */
		/* 0x00000279 02           */ IL_0001: ldarg.0
		/* 0x0000027A 0A           */ IL_0002: stloc.0
		/* (27,9)-(27,10) C:\Users\admin\source\repos\ClassLibrary6\ClassLibrary6\Class1.cs */
		/* 0x0000027B 2A           */ IL_0003: ret
	} // end of method Class1::Box

	// Token: 0x06000003 RID: 3 RVA: 0x0000207C File Offset: 0x0000027C
	.method private hidebysig static 
		void BoxRef<class T1> (
			!!T1 it
		) cil managed 
	{
		// Header Size: 12 bytes
		// Code Size: 4 (0x4) bytes
		// LocalVarSig Token: 0x11000001 RID: 1
		.maxstack 1
		.locals init (
			[0] !!T1 ol
		)

		/* (30,9)-(30,10) C:\Users\admin\source\repos\ClassLibrary6\ClassLibrary6\Class1.cs */
		/* 0x00000288 00           */ IL_0000: nop
		/* (32,13)-(32,21) C:\Users\admin\source\repos\ClassLibrary6\ClassLibrary6\Class1.cs */
		/* 0x00000289 02           */ IL_0001: ldarg.0
		/* 0x0000028A 0A           */ IL_0002: stloc.0
		/* (33,9)-(33,10) C:\Users\admin\source\repos\ClassLibrary6\ClassLibrary6\Class1.cs */
		/* 0x0000028B 2A           */ IL_0003: ret
	} // end of method Class1::BoxRef

	// Token: 0x06000004 RID: 4 RVA: 0x0000208C File Offset: 0x0000028C
	.method public hidebysig specialname rtspecialname 
		instance void .ctor () cil managed 
	{
		// Header Size: 1 byte
		// Code Size: 8 (0x8) bytes
		.maxstack 8

		/* 0x0000028D 02           */ IL_0000: ldarg.0
		/* 0x0000028E 280F00000A   */ IL_0001: call      instance void [mscorlib]System.Object::.ctor()
		/* 0x00000293 00           */ IL_0006: nop
		/* 0x00000294 2A           */ IL_0007: ret
	} // end of method Class1::.ctor

	// Token: 0x06000005 RID: 5 RVA: 0x00002095 File Offset: 0x00000295
	.method private hidebysig specialname rtspecialname static 
		void .cctor () cil managed 
	{
		// Header Size: 1 byte
		// Code Size: 17 (0x11) bytes
		.maxstack 8

		/* (13,9)-(13,26) C:\Users\admin\source\repos\ClassLibrary6\ClassLibrary6\Class1.cs */
		/* 0x00000296 17           */ IL_0000: ldc.i4.1
		/* 0x00000297 8001000004   */ IL_0001: stsfld    int32 ClassLibrary6.Class1::i
		/* (14,9)-(14,41) C:\Users\admin\source\repos\ClassLibrary6\ClassLibrary6\Class1.cs */
		/* 0x0000029C 730F00000A   */ IL_0006: newobj    instance void [mscorlib]System.Object::.ctor()
		/* 0x000002A1 8002000004   */ IL_000B: stsfld    object ClassLibrary6.Class1::i2
		/* 0x000002A6 2A           */ IL_0010: ret
	} // end of method Class1::.cctor

} // end of class ClassLibrary6.Class1

在这里插入图片描述

没有发生装拆箱,是之间call调用了对于的函数。

在这里插入图片描述
我们发现它只是把 0号位置的参数推入计算堆栈并弹出,其他并没什么了。

就有点像C++的内联函数一样,提前生成对应的代码段,通过占位的方式避免装拆箱(不知道这么解释对不对)

总结几点:
1.装拆箱代IL码量少,但是太多性能低下。
2.泛型IL代码量多,但是避免了装拆箱,在目前的PC和移动平台下,基本可以不用考虑(内存换性能)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值