《Unity3D高级编程 主程手记》第二章 C#技术要点(五) 委托、事件、装箱、拆箱

        在 C# 中指针被封装在内部函数当中。不过回调函数却依然存在,于是 C# 多了一个委托(delegate)的概念,所有函数指针都以委托的方式来完成的。委托可以被视为一个更高级的函数指针,它不仅仅能把地址指向另一个函数,而且还能传递参数获得返回值等多个信息。系统还为委托对象自动生成了同步、异步的调用方式,开发人员使用 BeginInvoke()、EndInvoke() 方法就可以避开 Thread 类,从而直接使用多线程调用

委托(delegate)

        委托不是一个语言的基本类型,创建委托 delegate 时其实就是创建了一个 delegate 类实例。

        BeginInvoke()、EndInvoke()、Invoke():异步开始调用、异步结束调用、直接调用。

        存储函数地址的变量是个可变数组,可以认为是个链表,每次直接赋值时会换一个链表。

        当对函数操作 += 和 -= 时,相当于把函数地址推入了链表尾部,或者移出了链表。

        当委托被调用时,委托实例会把所有链表里的函数依次按顺序用传进来的参数调用一遍。

事件(event)

        在委托 delegate 上,又做了一次封装,限制用户直接操作 delegate 实例中变量的权限。

        event 声明的委托不再提供 ‘=’ 的操作符,但仍然有 ‘+=’ 和 ‘-=’ 的操作符可供操作。

        申明 event 后,编译器内部重新封装了委托,让暴露在外面的委托不再担心随时被清空和重置的危险。

        这样就保证了谁注册就必须谁负责销毁的目的,更好的维护了 delegate 的秩序。

装箱和拆箱

        把值类型实例转换为引用类型实例,就是装箱。相反,把引用类型实例转换为值类型实例,就是拆箱

        栈是本着先进后出的数据结构(LIFO)原则的存储机制,它是一段连续的内存,所以对栈数据的定位比较快速, 而堆则是随机分配的空间, 处理的数据比较多, 无论如何, 至少要两次定位。堆内存的创建和删除节点的时间复杂度是 O(logn)。栈创建和删除的时间复杂度则是O(1),栈速度更快。

    那么既然栈速度这么快,全部用栈不就好了。这又涉及到生命周期问题,由于栈中的生命周期是必须确定的,销毁时必须按次序销毁,从最后分配的块部分开始销毁,创建后什么时候销毁必须是一个定量,所以在分配和销毁时不灵活,基本都用于函数调用和递归调用中,这些生命周期比较确定的地方。相反堆内存可以存放生命周期不确定的内存块,满足当需要删除时再删除的需求,所以堆内存相对于全局类型的内存块更适合,分配和销毁更灵活。

        大部分时候只有当程序、逻辑或接口需要更加通用的时候才会需要装箱。 

装箱的内部操作:

  • 装箱: 根据相应的值类型在堆中分配一个值类型内存块,再将数据拷贝给它。按三步进行。
  • 第一步:在内存中新分配一个内存块(大小为值类型实例大小加上一个方法表指针和一个SyncBlockIndex 类)。
  • 第二步:将值类型的实例字段拷贝到新分配的内存块中。
  • 第三步:返回内存堆中新分配对象的地址

拆箱:检查对象实例,确保它是给定值类型的一个装箱值,再将该值从实例复制到值类型变量的内存块中。

装箱、拆箱对执行效率的影响和优化

        由于装箱、拆箱时生成的是全新的对象,不断得分配和销毁内存会不但大量消耗 CPU,也同时增加了内存碎片,降低了性能。

        Struct 变化后的优化方法:

  1. Struct 通过重载函数来避免拆箱、装箱;如:ToString(),GetType()
  2. 通过泛型来避免拆箱、装箱;如:struct B、C 继承 A => 泛型方法 void Test(T t) where T : A
  3. 通过继承统一的接口提前拆箱、装箱,避免多次重复拆箱、装箱。如:Struct A 和 Struct B 都继承接口 I => 调用的方法是 void Test(I i)。

        当调用 Test 方法时传进去的 Struct A 或 Struct B 的实例都相当于提前做了装箱操作,Test 里拿到的参数后就不用再担心内部再次装箱拆箱问题了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值