Unity游戏开发经验分享

Unity - C#进阶

2020-12-15  本文已影响0人  能不写代码么

1. 堆、栈、队列

堆栈都是一种数据项按序排列的数据结构,栈只能在一端对数据项进行插入或删除

堆的理解

  1. 堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质:
    ·堆中某个节点的值总是不大于或不小于其父节点的值;
    ·堆总是一棵完全二叉树。
    将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。

  2. 堆是在程序运行时,而不是在程序编译时,申请某个大小的内存空间。即动态分配内存,对其访问和对一般内存的访问没有区别。

  3. 堆是应用程序在运行的时候请求操作系统分配给自己内存,一般是申请/给予的过程。

  4. 堆是指程序运行时申请的动态内存,而栈只是指一种使用堆的方法(即先进后出)。

栈的理解

  1. 栈(stack)又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。

  2. 栈就是一个桶,后放进去的先拿出来,它下面本来有的东西要等它出来之后才能出来(先进后出)

队列的理解

  1. 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

  2. 队列中没有元素时,称为空队列。

区别点:
栈只允许在表尾一端进行插入和删除,队列只允许在表尾一端进行插入,在表头一端进行删除。

常用于:
队列常用于做一个固定顺序的任务系统
栈常用语做 UIManager管理系统 后进先出的原则,最后打开的界面,优先取出关闭。

具体代码中使用:

//定义一个栈
 private Stack<GameObject>myStack=new Stack<GameObject>();
//push是入栈
 myStack.Push(gameobject01);
//pop是取栈顶元素,并删除,还有一个方法是peek也是取栈顶元素,但是不删除
 GameObject gameobject01= Stack.Pop();

队列

//new一个int类型的队列
Queue<int> queue=new Queue<int> ();
//属性Count,获取 Queue 中包含的元素个数。
if(queue.Count==0)
//从 Queue 中移除所有的元素
queue.Clear();
//判断某个元素是否在 queue 中
queue.Contains( 5);
//移除并返回在 Queue 的开头的对象
int number=queue.Dequeue()
//向 Queue 的末尾添加一个对象
queue.Enqueue( 5 );
//复制 Queue 到一个新的数组中
public virtual object[] ToArray();
//设置容量为 Queue 中元素的实际个数
queue.TrimToSize();

2. 值类型、引用类型

值类型:在C#中,继承自System.ValueType的类型被称为值类型,主要有以下几种(CLR2.0中支持类型有增加): * bool * byte * char * decimal * double * enum * float * int * long * sbyte * short * struct * uint * ulong * ushort

引用类型:继承自System.Object: * class * interface * delegate * object * string *StringBuilder

混淆点

  1. 经常混淆的是string。有人说String变量比string变量效率高;还听说String是引用类型,string是值类型,等等。例如:
string s1 = "Hello, " ;
string s2 = "world!" ;
string s3 = s1 + s2;//s3 is "Hello, world!"

这确实看起来像一个值类型的赋值,再比如改变s1的值对s2没有影响。这更使string看起来像值类型。实际上,这是运算符重载的结果,当s1被改变时,.NET在托管堆上为s1重新分配了内存。这样的目的,是为了将做为引用类型的string实现为通常语义下的字符串。

string s1 = "a" ;
string s2 = s1 ;
s1 = "b";//s2 is still "a"

2.Unity对transform.position.x/y/z直接赋值时就会报错
因为transform.position是结构体,结构体是值类型。当我们写出形如 transform.position.x = 1 这样的代码时,是在通过get方法得到position,然后修改position的x字段的值。但是由于position是结构体类型的,get得到的也只是position的一个副本,而对这个副本所作出的任何修改,都对原positon没有任何影响,因此这样的修改是毫无意义的。编译器会禁止这样的修改操作
通过查看源码,可以看到position不是一个共有字段,是一个属性。要对结构体的共有字段进行修改是不会有问题的。这里我觉得修改transform.position没问题是因为set时传递了ref参数,也就是引用,所以是有意义的

总结
相同点:

  1. 引用类型可以实现接口,值类型当中的结构体也可以实现接口;
  2. 引用类型和值类型都继承自System.Object类。

不同点:

  1. 引用类型总是存放在堆中;
  2. 值类型和指针总是存放在它们本声明的地方;
  3. 栈有1个特点,就是空间较小,但是访问速度较快
  4. 堆空间较大,但是访问速度相对较慢

堆:我们声明的游戏对象都存放在堆中,当堆中的内存不够分配时会触发GC,如果GC之后内存还是不够,会扩大堆得内存,所以当堆的内存分配越来越大就会影响游戏的性能。
栈:主要负责存放代码运行的路径,
比如我们debug的时候就会输出堆栈回溯,在调试时能够很方便的查看代码的运行的路径,即栈回溯信息


3. string、StringBuffer、StringBuilder

string:一旦赋值或实例化后就不可更改,如果赋予新值将会重新开辟内存地址进行存储
StringBuilder:如果我们对字符串进行拼接,每次拼接都会创建一个String对象,消耗时间和资源,而StringBuilder是一个可变的字符串,用append和insert等方法改变字符串值时只是在原有对象存储的内存地址上进行连续操作,减少了资源的开销

区别:
执行速度方面的比较: StringBuilder >StringBuffer > String
字符串拼接时,String 对象的速度并不会比 StringBuffer对象慢

  1. String的内容是固定的,StringBuilder的内容是可变的
  2. StringBuffer和StringBuilder是一样的,后者速度比前者快,但是前者是线程安全的,适合在多线程下使用,后者是线程非安全的,比较适合在单线程下使用

4. ref、out、parpms

public class NewBehaviourScript : MonoBehaviour
{
    void Start()
    {
        int testRef01 = 1;
        int testRef02 = 2;
        TestRef(ref testRef01 , ref testRef02);
        Debug.Log(testRef01);
        Debug.Log(testRef02);
    }

    public void TestRef(ref int param1 , ref int param2)
    {
        param1 = 111;
        Debug.Log(param1);
        param2 = 222;
        Debug.Log(param2);
    }
}
打印结果
public class NewBehaviourScript : MonoBehaviour
{
    void Start()
    {
        int testRef03;
        int testRef04;
        TestOut(out testRef03, out testRef04);
        Debug.Log(testRef03);
        Debug.Log(testRef04);
    }

    public void TestOut(out int param1, out int param2)
    {
        param1 = 333;
        param2 = 444;
    }
}
打印结果
out进来的值默认是空的
public class NewBehaviourScript : MonoBehaviour
{
    void Start()
    {
        TestParams(1,2,3);
    }

    public void TestParams(params int[] param)
    {
        foreach (var p in param)
        {
            Debug.Log(p);
        }
    }
}
打印结果

5. Struct 和 Class

区别
Struct 是值类型
Class 是引用类型
何时使用
Struct :

  1. 当我们描述1个轻量级对象的时候,可以将其定义为结构来提高效率.比如点,矩形,颜色,这些对象是轻量级的对象,因为描述他们,只需要少量的字段
  2. 我们在变量传值的时候,我就是希望传递对象的拷贝,而不是对象的引用地址,那么这个时候也可以使用结构了

Class : 当描述1个重量级对象的时候,我们知道类的对象是存储在堆空间中的,我们就将重量级对象定义为类. 他们都表示可以包含数据成员和函数成员的数据结构


上一篇 下一篇

猜你喜欢

热点阅读