一、Unity开发相关 C#代码
1、C#中四种访问修饰符是哪些?各有什么区别?
四种访问修饰符:属性修饰符、存取修饰符、类修饰符、成员修饰符
a. 属性修饰符:
Serializable: 按值将对象封装送到远程服务器;
STATread:是单线程套间意思,是一种线程模型;
MATAThread:是多线程套间意思,也是一种线程模型;
b. 存取修饰符 :
public:存取不受限制;
private:只有包含该成员的类可以存取;
internal:只有当前命名空间可以存取。只能在包含该类的程序集中访问该类;
protected:只有包含该成员的类及派生类可以存取
c. 类修饰符:
abstract:抽象类,指一个类只能作为其他类的基类;
sealed:密封类,指一个类不能被继承
d. 成员修饰符:
abstract:指示该方法或属性没有实现。
sealed:密封方法。可以防止在派生类中对该方法的override(重载)。不是类的每个成员方法都可以作为密封方法密封方法,必须对基类的虚方法进行重载,提供具体的实现方法。所以,在方法的声明中,sealed修饰符总是和override修饰符同时使用。
delegate:委托。用来定义一个函数指针。C#中的事件驱动是基于delegate + event的。
const:指定该成员的值只读不允许修改。
event:声明一个事件。
extern:指示方法在外部实现。
override:重写。对由基类继承成员的新实现。
readonly:指示一个域只能在声明时以及相同类的内部被赋值。
static:指示一个成员属于类型本身,而不是属于特定的对象。即在定义后可不经实例化,就可使用。
2、ArrayList和List主要区别?
a. ArrayList存在不安全类型,ArrayList会把所有插入其中的数据都当做Object处理、装箱拆箱操作;
b.List是接口,ArrayList是一个实现了该接口的类,可以被实例化;
3、简述GC(垃圾回收)产生的原因,如何避免?
产生的原因:回收堆上的内存
避免:
a. 减少new 产生对象的次数
b. 使用公用的对象(静态成员)
c. 将String换为StringBuilde
4、Heap和Stack有和区别?
a. Heap是堆,Stack是栈;
b. Stack的空间由操作系统自动分配和释放,Heap的空间是手动申请和释放的,Heap通常用new关键词分配;
c.Stack空间有限,Heap空间有很大自由区。
5、值类型和引用类型区别?
a. 值类型的数据存储在内存的栈中;引用类型存储在内存的堆中;
b. 值类型存取速度快,引用类型存取速度慢;
c. 值类型表示实际数据,引用类型表示指向存储在内存堆中的数据的指针或引用。
d. 栈的内存分配是自动释放;堆在.NET会有GC来释放
6、结构体和类的区别?
结构体是一种值类型,而类是引用类型。
值类型存储数据的值,引用类型用于存储实际数据的引用。
结构体是当值来使用的,类通过引用来实现对数据操作。
7、ref参数和out参数是什么?有什么区别?
ref和out参数的效果一样,都是通过关键字找到定义在主函数的变量的内存地址,通过方法体内的语法改变它的大小。
区别:
a. 输出参数必须对参数进行初始化;
b. ref参数是引用,out参数是输出参数。ref修饰参数,表示进行引用传递,out修饰参数也表示进行引用传递,但传递的引用只为带回返回值
c. ref又进又出,out不进只出。
8、C#中的代理和事件?
代理是定义指向方法的引用,C#事件本质是对消息的封装,用作对象之间的通信;发送方叫事件的发送器,接收方叫事件接收器。
9、客户端和服务器交互的方式有几种?
Socket 通常也称“套接字”,实现服务器和客户端之间的物理连接,并进行数据传输,主要是UDP和TCP两个协议。Socket处于网络协议的传输层。
HTTP协议传输主要有Http协议和基于Http协议的Soap协议(WebService),常见的方式是Http的Post和Get请求服务。
10、能用foreach遍历访问的对象需要实现接口或声明方法的类型
IEnumerable接口,GetEnumerator方法
11、C# String类型比StringBuilder类型的优势是什么?
a. 如果是处理字符串的话,用String中的方法每次都需要创建一个新的字符串对象并且分配新的内存地址,而 StringBuilder 是在原来的内存里对字符串进行修改,所以在字符串处理方面还是建议用stringBuilder这样比较节约内存。但是 string 类的方法和功能仍然还是比 stringBuilder 类要强。
b. String类由于具有不可变性(即对一个 string 对象进行任何更改时,其实都是创建另外一个 string 类的对象),所以当需要频繁的对一个 string 类对象进行更改的时候,建议使用StringBuilder 类,StringBuilder 类的原理是首先在内存中开辟一定大小的内存空间,当对此 StringBuilder 类对象进行更改时, 如果内存空间大小不够, 会对此内存空间进行扩充,而不是重新创建一个对象,这样如果对一个字符串对象进行频繁操作的时候,不会造成过多的内存浪费,其实本质上并没有很大区别,都是用来存储和操作字符串的,唯一的区别就在于性能上。
c. String主要用于公共 API,通用性好、用途广泛、读取性能高、占用内存小。
d. StringBuilder主要用于拼接 String,修改性能好。不过现在的编译器已经把String的 + 操作优化成 StringBuilder 了, 所以一般用String 就可以了。
e. String是不可变的,所以天然线程同步。
f. StringBuilder可变,非线程同步。
12、C#中有哪些常用的容器类,各有什么特点?
容器类:List,Hash,Table,Dictionary,Stack,Queue
a. List:索引泛型容器,访问速度快,修改速度慢;
b.HashTable/Dictionary:散列表格式,查询效率高,空间占用较大;
c. Stack:后进先出
d.Queue:先进后出
13、函数中多次使用string的+=处理,会产生大量内存垃圾(垃圾碎片),有什么好的方法可以解决?
通过StringBuilder那进行Append,这样可以减少内存垃圾。
14、用鼠标实现在场景中拖动物体,用鼠标滚轮实现缩放(用一个Cube 即可)。
在场景中添加一个Plan,Camera,Directional Light,Cube。添加两个脚本scrollerScirpt(挂在Camera),CubeDragScript(挂在Cube上)
a.鼠标滚轮实现缩放:将摄像机的镜头拉近或者拉远,调整摄像机的视角就可以实现,主要实现代码如下
void Update () {
//鼠标滚轮的效果
if (Input.GetAxis("Mouse ScrollWheel") < 0) {
if (Camera.main.fieldOfView <= 100)
Camera.main.fieldOfView += 2;
if (Camera.main.orthographicSize <= 20)
Camera.main.orthographicSize += 0.5F;
}
//Zoom in
if (Input.GetAxis("Mouse ScrollWheel") > 0) {
if (Camera.main.fieldOfView > 2)
Camera.main.fieldOfView -= 2;
if (Camera.main.orthographicSize >= 1)
Camera.main.orthographicSize -= 0.5F;
}
}
b.鼠标实现在场景中拖动物体:
解决思路就是将世界坐标转换成屏幕坐标,然后计算物体与鼠标之间移动量,循环鼠标被按下操作,得到鼠标的当前位置,加上计算好的移动量,将新的坐标赋值给物理就行了。主要是开启一个协同程序(Corountine)来处理。主要代码如下:
// Use this for initialization
void Start () {
StartCoroutine(OnMouseDown());
}
IEnumerator OnMouseDown() {
//将物体由世界坐标系转换为屏幕坐标系
Vector3 screenSpace = Camera.main.WorldToScreenPoint(transform.position);
//完成两个步骤 1.由于鼠标的坐标系是2维,需要转换成3维的世界坐标系
//2.只有3维坐标情况下才能来计算鼠标位置与物理的距离,offset即是距离
//将鼠标屏幕坐标转为三维坐标,再算出物体位置与鼠标之间的距离
Vector3 offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpace.z));
while (Input.GetMouseButton(0)) {
//得到现在鼠标的2维坐标系位置
Vector3 curScreenSpace = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpace.z);
//将当前鼠标的2维位置转换成3维位置,再加上鼠标的移动量
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenSpace) + offset;
//curPosition就是物体应该的移动向量赋给transform的position属性
transform.position = curPosition;
yield return new WaitForFixedUpdate(); //这个很重要,循环执行
}
}
14、ITween插件的作用是什么,ITween作用于世界坐标还是局部坐标,请列举三个常用方法?
iTween是一个动画库,作者创建它的目的就是最小的投入实现最大的产出,轻松实现各种动画,晃动,旋转,移动,褪色,上册,控制音频:
a. MoveTo 物体移动;
b. ColorTo:随着时间改变对象颜色组;
c. LookTo:随着时间旋转物体让其脸部朝向所提供的位置