当前位置:   article > 正文

Unity中有关C#的几个要点_unity system.multicastdelegate

unity system.multicastdelegate

转载https://nickcan.gitee.io/2018/02/25/Unity%E4%B8%AD%E6%9C%89%E5%85%B3C-%E7%9A%84%E5%87%A0%E4%B8%AA%E8%A6%81%E7%82%B9/

大致总结下C#中几个常见知识点的个人理解,以对基础已经有所了解为前提。不定期更新~!

ref/out

  • 区别:ref参数需要在传入前就初始化,out参数在函数结束前需要至少赋值一次。
  • 用处:1.需要返回多个数值的时候 2.需要修改值类型参数 或者 不希望传入值类型参数时发生Copy。
  • 原理:ref参数解析出来,其实传入的是参数的存储地址,类似C++的&地址符。out也一样。从而实现像修改引用类型一样,修改值类型。
    深度思考ref和out及其使用情景
  1. void RefOutTest()
  2. {
  3. int a;
  4. // refTest(ref a);//error: a需要先初始化
  5. a = 1;
  6. refTest(ref a);
  7. outTest(out a);
  8. Debug.Log("out - " + a);// out - 2
  9. }
  10. void RefTest(ref int a)
  11. {
  12. }
  13. void OutTest(out int a)
  14. {
  15. a = 2;
  16. }

string

  • string 是引用类型哦~!看着像是值类型,实际上是因为每次对string操作,它都会返回一个新的string,所以看起来就跟值类型一样,直接改变了值。
  • 比较惊讶的是!同样的字符串内容,在堆内存中只保留一份。感觉有点像是,一种字符串,便是一个静态类实例。
    net中String是引用类型还是值类型
  1. string str1 = "abc";
  2. string str2 = "abc";
  3. Debug.Log(object.ReferenceEquals(str1, str2)); //true
  4. Debug.Log(object.ReferenceEquals(str1, "abc")); //true!!

装拆箱

  • 装箱:从值类型到引用类型,从栈到堆。(int转为object)涉及到 1.在堆中开辟空间 2.把值类型的值复制到新开辟的空间中(可以理解成new了一个class,然后把复制到其中一个成员变量里)
  • 拆箱:从引用类型变回值类型,从堆到栈。(object转为int)涉及到 1.从引用获取到堆中的存储位置 2.复制到栈中
  • 因为涉及到申请内存空间,当已分配的内存空间不足时,就会触发GC,引起后续一系列性能消耗,所以要避免频繁的装箱拆箱。

迭代器

  • IEnumrable:IEnumrator GetEnumrator()。
  • IEnumrator: object Current,bool MoveNext(),Reset()。
  • Enumrator实际上是被解析成一个类,类通过简单的状态机(MoveNext)控制实现迭代器。而IEnumrable提供一个获取迭代器的方法,本质上是 new 一个 Enumrator类,并返回。
  • Enumrator状态分为 before,running,suspended,after 四个状态,在MoveNext中通过switch-case来实现状态机。
  • 迭代器是迭代器模式和状态模式的混合。
  • StartCoroutine的参数类型是IEnumrator,而不是IEnumrable。
  • foreach 会自动调用 IEnumrable.GetEnumrator 从而通过迭代器实现遍历。
    匹夫细说C#:庖丁解牛迭代器,那些藏在幕后的秘密
  1. void Start()
  2. {
  3. var enumerator = EnumerableTest().GetEnumerator();
  4. Debug.LogError(enumerator.Current);
  5. Debug.LogError(enumerator.MoveNext());
  6. Debug.LogError(enumerator.Current);
  7. //两个输出结果一致
  8. StartCoroutine(EnumerableTest().GetEnumerator());
  9. StartCoroutine(EnumeratorTest());
  10. }
  11. IEnumerable EnumerableTest()
  12. {
  13. Debug.Log(1);
  14. yield return new WaitForSeconds(.5f);
  15. Debug.Log(2);
  16. yield return new WaitForSeconds(.5f);
  17. Debug.Log(3);
  18. }
  19. IEnumerator EnumeratorTest()
  20. {
  21. var enumerator = EnumerableTest().GetEnumerator();
  22. while(enumerator.MoveNext())
  23. {
  24. yield return enumerator.Current;
  25. }
  26. }

GC(Garbage Collector 垃圾收集器)

  • GC大致过程:首先需要挂起所有托管线程,然后扫描还活着的对象,释放空间,最后恢复线程。扫描过程可能会改变数据在堆中的存放位置,腾出新空间,将已使用和空间的空间重新排列分开,于是同时也要改变栈上堆上的指针指向,如果空间还不够,则要申请更多的空间。
  • GC会自动定时执行,也可手动执行。
  • 减少GC,就要减少不必要的堆内存分配了。比如使用对象池复用一些频繁创建的对象。
  • 影响GC速度的是堆中对象的数量,越多则越慢。
  • 基本算法:1.将所有托管内存标记为垃圾 2.遍历内存块,将在使用的内存块标记为有效 3.释放所有无效的内存块 4.整理堆,减少碎片
    C#知识点扫盲-GC

委托和事件

  • 委托本质上是一个类,继承了System.MulticastDelegate。
  • 三个重要的非公有字段: _target (该委托的实例引用,比如委托指向的方法为类a的某个方法则 target=a), _methodPtr(回调函数(方法)的句柄),_invocationList(一个委托数组,通过System.Delegate.Combine连接两个委托就是将后面的委托加到前面委托的 _invocationList中)。
  • 委托实际上是包装了 执行操作的对象 和 对象要执行的方法 的包装器(类)。

  • 事件本质上是对System.Delegate和委托的封装而已,根本上是通过调用System.Deleagte.Combine等方法对delegate操作的一个委托管理器。
    匹夫细说C#:庖丁解牛聊委托,那些编译器藏的和U3D给的

闭包

  • 闭包:一个方法除了能和传递给它的参数交互之外,还可以同上下文进行更大程度的互动。实际上就是匿名函数会把使用到的变量都保存到自己的类中。
  • 所以局部变量不一定就在栈上,也可能在堆上。(类中的值类型成员是和该类一起存放于堆中的)

容器(数据结构)

Array 数组

  • 固定长度
  • 连续存储

ArrayList 数组

  • 类型不安全(存储类型为object),会发生装箱拆箱,也因此可以存放各种不同类型的值。
  • 可变长,插入方便。

List 数组

  • 类型安全的ArryList。

LinkedList 链表

  • 不连续存储。
  • 增删插入都很方便,只需要修改next指针,但是查找就没数组来的方便了,数组直接用下标。

Queue 队列

  • 本质是数组,环形的数组。
  • 通过一个 head 和 tail 变量来指定该数组的头和尾。
  • 长度不够时,也会和数组一样自动扩容。(因为本质就是用数组来存储数据的)

Stack 栈

  • 本质是数组,垂直的数组。
  • 头和尾不用指定了,就是0和count-1了。
  • 长度不够,自动扩容。同上。

HashTable 散列表

  • 类型不安全。
  • 通过特定的哈希函数,对Key加工,得到一个压缩后的哈希值(数字组成,用来当做数组下标)。哈希值是数组下标!?
  • 冲突避免机制:选择合适的哈希函数
  • 冲突解决机制:如果不同的Key得到了一样的哈希值,这时要采取一定的策略(有规则的)保存他们。
  • HashTable采用的双重哈希(二度哈希)来解决冲突,通过更换哈希函数来解决,据说如果发生冲突,则会导致所有哈希被重新计算。

Dictionary 字典

  • 类型安全的HashTable。
  • 采用链接技术(Chaining)来解决冲突,用额外的数据结构来处理冲突。
  • 一个字典,实际上由 int[] buckets 和 Entry[] entries 两个数组组成。
  • buckets保存指定哈希值对应的数据在哈希表中的下标。
  • entries保存数据链表,即Entry实际上是一个链表类型的数据结构。
  • 如果两个数据拥有同一个哈希值,那么他们会以链表的形式,连接在同一个Entry中。

使用

  • 数组:元素数量固定,需要使用下标
  • 链表:当元素需要能够在列表两端添加时,否则使用List
  • 队列和栈:明确的场景 FIFO,LILO
  • 哈希表和字典:需要使用键值对(key-value)来快速添加和查找,并且元素没有特定顺序时。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/527593
推荐阅读
相关标签
  

闽ICP备14008679号