unity学习之汇总解答

C#基础:

1.封装、继承、多态所处位置不同,重载在同类中,重写在父子类中。

2.定义方式不同,重载方法名相同参数列表不同,重写方法名和参数列表都相同。

3.调用方式不同,重载使用相同对象以不同参数调用,重写用不同对象以相同参数调用。

4.多态时机不同,重载时编译时多态,重写是运行时多态。

2.面向对象的三大特点

1.继承:提高代码重用度,增强软件可维护性的重要手段,符合开闭原则。继承最主要的作用就是把子类的公共属性集合起来,便与共同管理,使用起来也更加方便。你既然使用了继承,那代表着你认同子类都有一些共同的特性,所以你把这些共同的特性提取出来设置为父类。继承的传递性:传递机制 a▶b; b▶c; c具有a的特性 。继承的单根性:在C#中一个类只能继承一个类,不能有多个父类。

2.封装:封装是将数据和行为相结合,通过行为约束代码修改数据的程度,增强数据的安全性,属性是C#封装实现的最好体现。就是将一些复杂的逻辑经过包装之后给别人使用就很方便,别人不需要了解里面是如何实现的,只要传入所需要的参数就可以得到想要的结果。封装的意义在于保护或者防止代码(数据)被我们无意中破坏。

3.多态性:多态性是指同名的方法在不同环境下,自适应的反应出不同得表现,是方法动态展示的重要手段。多态就是一个对象多种状态,子类对象可以赋值给父类型的变量。

3.简述值类型和引用类型有什么区别

值类型:包含了所有简单类型(整数、浮点、bool、char)、struct、enum。
继承自System.ValueTyoe
引用类型包含了string,object,class,interface,delegate,array
继承自System.Object

1.值类型存储在内存栈中,引用类型数据存储在内存堆中,而内存单元中存放的是堆中存放的地址。

2.值类型存取快,引用类型存取慢。

3.值类型表示实际数据,引用类型表示指向存储在内存堆中的数据的指针和引用。

4.栈的内存是自动释放的,堆内存是.NET 中会由 GC 来自动释放。

5.值类型继承自 System.ValueType,引用类型继承自 System.Object。

6.值类型的变ᰁ直接存放实际的数据,⽽引⽤类型的
变ᰁ存放的则是数据的地址,即对象的引⽤。

7.值类型变量直接把变量的值保存在堆栈中,引⽤类
型的变量把实际数据的地址保存在堆栈中。

4.请简述private,public,protected,internal的区别

public:对任何类和成员都公开,无限制访问

private:仅对该类公开

protected:对该类和其派生类公开

internal:只能在包含该类的程序集中访问该类

protected internal:protected + internal

5.C#中所有引用类型的基类是什么

引用类型的基类是System.Object值类型的基类是 System.ValueType

同时,值类型也隐式继承自System.Object

6.请简述ArrayList和 List的主要区别

ArrayList 不带泛型 数据类型丢失

List 带泛型 数据类型不丢失

ArrayList 需要装箱拆箱 List不需要

ArrayList存在不安全类型(ArrayList会把所有插 ⼊其中的数据都当做Object来处理)装箱拆箱的 操作(费时)IList是接⼝,ArrayList是⼀个实现了 该接⼝的类,可以被实例化

List类是ArrayList类的泛型等效类。它的大部分用法都与ArrayList相似,因为List类也继承了IList接口。最关键的区别在于,在声明List集合时,我们同时需要为其声明List集合内数据的对象类型。

7.请简述GC(垃圾回收)产生的原因,并描述如何避免?

GC为了避免内存溢出而产生的回收机制

避免:
1)减少 new 产生对象的次数
2)使用公用的对象(静态成员)
3)将 String 换为 StringBuilder

8. 请描述Interface与抽象类之间的不同

1.接口不是类 不能实例化 抽象类可以间接实例化

2.接口是完全抽象 抽象类为部分抽象

3.接口可以多继承 抽象类是单继承

9.请简述关键字Sealed用在类声明和函数声明时的作用

类声明时可防止其他类继承此类,在方法中声明则可防止派生类重写此方法。

10. 反射的实现原理?

可以在加载程序运行时,动态获取和加载程序集,并且可以获取到程序集的信息反射即在运行期动态获取类、对象、方法、对象数据等的一种重要手段

主要使用的类库:System.Reflection

核心类:

1.Assembly描述了程序集

2.Type描述了类这种类型

3.ConstructorInfo描述了构造函数

4.MethodInfo描述了所有的方法

5.FieldInfo描述了类的字段

6.PropertyInfo描述类的属性

通过以上核心类可在运行时动态获取程序集中的类,并执行类构造产生类对象,动态获取对象的字段或属性值,更可以动态执行类方法和实例方法等。

11. .Net与 Mono 的关系?

.Net是一个语言平台,Mono为.Net提供集成开发环境,集成并实现了.NET的编译器、CLR 和基础类库,使得.Net既可以运行在windows也可以运行于 linux,Unix,Mac OS 等。

12. 在类的构造函数前加上static会报什么错?为什么?

构造函数格式为public+类名如果加上 static 会报错(静态构造函数不能有访问、型的对象,静态构造函数只执行一次;
运行库创建类实例或者首次访问静态成员之前,运行库调用静态构造函数;
静态构造函数执行先于任何实例级别的构造函数;
显然也就无法使用this和 base 来调用构造函数。
一个类只能有一个静态函数,如果有静态变量,系统也会自动生成静态函数

13.C# String类型比 stringBuilder 类型的优势是什么?

如果是处理字符串的话,用string中的方法每次都需要创建一个新的字符串对象并且分配新的内存地址,而 stringBuilder 是在原来的内存里对字符串进行修改,所以在字符串处理

方面还是建议用stringBuilder这样比较节约内存。但是 string 类的方法和功能仍然还是比 stringBuilder 类要强。

string类由于具有不可变性(即对一个 string 对象进行任何更改时,其实都是创建另外一个 string 类的对象),所以当需要频繁的对一个 string 类对象进行更改的时候,建议使用StringBuilder 类,StringBuilder 类的原理是首先在内存中开辟一定大小的内存空间,当对此 StringBuilder 类对象进行更改时, 如果内存空间大小不够, 会对此内存空间进行扩充,而不是重新创建一个对象,这样如果对一个字符串对象进行频繁操作的时候,不会造成过多的内存浪费,其实本质上并没有很大区别,都是用来存储和操作字符串的,唯一的区别就在于性能上。

String主要用于公共 API,通用性好、用途广泛、读取性能高、占用内存小。

StringBuilder主要用于拼接 String,修改性能好。

不过现在的编译器已经把String的 + 操作优化成 StringBuilder 了, 所以一般用String 就可以了

String是不可变的,所以天然线程同步。

StringBuilder可变,非线程同步。

14.C#函数 Func(string a, string b)用 Lambda 表达式怎么写?

(a,b) => {};

15. 数列1,1,2,3,5,8,13…第 n 位数是多少?用 C#递归算法实现

public int CountNumber(int num) {
       if (num == 1 || num == 2) {
           return 1;
       } else {
           return CountNumber(num -1) + CountNumber(num-2);
       }
  }

16. 冒泡排序(手写代码)

public static void BubblingSort(int[]array) {

      for (int i = 0; i < array.Length; i++){
     
          for (int j = array.Length - 1; j > 0; j--){
         
              if (array[j] < array[i]) {
             
                  int temp = array[j];
                  array[j] = array[j-1];
                  array[j - 1] = temp;
              }
          }
      }
  }

17. C#中有哪些常用的容器类,各有什么特点。

List,HashTable,Dictionary,Stack,Queue

Stack栈:先进后出,入栈和出栈,底层泛型数组实现,入栈动态扩容2倍

Queue队列:先进先出,入队和出队,底层泛型数组实现,表头表尾指针,判空还是满通过size比较
Queue和Stack主要是用来存储临时信息的

Array数组:需要声明长度,不安全

ArrayList数组列表:动态增加数组,不安全,实现了IList接口(表示可按照索引进行访问的非泛型集合对象),Object数组实现

List列表:底层实现是泛型数组,特性,动态扩容,泛型安全
将泛型数据(对值类型来说就是数据本身,对引用类型来说就是引用)存储在一个泛型数组中,添加元素时若超过当前泛型数组容量,则以2倍扩容,进而实现List大小动态可变。(注:大小指容量,不是Count)

LinkList链表
1、数组和List、ArrayList集合都有一个重大的缺陷,就是从数组的中间位置删除或插入一个元素需要付出很大的代价,其原因是数组中处于被删除元素之后的所有元素都要向数组的前端移动。
2、LinkedList(底层是由链表实现的)基于链表的数据结构,很好的解决了数组删除插入效率低的问题,且不用动态的扩充数组的长度。
3、LinkedList的优点:插入、删除元素效率比较高;缺点:访问效率比较低。

HashTable哈希表(散列表)
概念:不定长的二进制数据通过哈希函数映射到一个较短的二进制数据集,即Key通过HashFunction函数获得HashCode
装填因子:α=n/m=0.72 ,存储的数据N和空间大小M
然后通过哈希桶算法,HashCode分段,每一段都是一个桶结构,一般是HashCode直接取余。
桶结构会加剧冲突,解决冲突使用拉链法,将产生冲突的元素建立一个单链表,并将头指针地址存储至Hash表对应桶的位置。这样定位到Hash表桶的位置后可通过遍历单链表的形式来查找元素。
1、Key—Value形式存取,无序,类型Object,需要类型转换。
2、Hashtable查询速度快,而添加速度相对慢
3、Hashtable中的数据实际存储在内部的一个数据桶里(bucket结构体数组),容量固定,根据数组索引获取值。

//哈希表结构体
private struct bucket {
   public Object key;//键
    public Object val;//值
    public int hash_col;//哈希码
}
//字典结构体
private struct Entry {
    public int hashCode;    // 除符号位以外的31位hashCode值, 如果该Entry没有被使用,那么为-1
    public int next;        // 下一个元素的下标索引,如果没有下一个就为-1
    public TKey key;        // 存放元素的键
    public TValue value;    // 存放元素的值
}

private int[] buckets;      // Hash桶
private Entry[] entries;    // Entry数组,存放元素
private int count;          // 当前entries的index位置
private int version;        // 当前版本,防止迭代过程中集合被更改
private int freeList;       // 被删除Entry在entries中的下标index,这个位置是空闲的
private int freeCount;      // 有多少个被删除的Entry,有多少个空闲的位置
private IEqualityComparer<TKey> comparer;   // 比较器
private KeyCollection keys;     // 存放Key的集合
private ValueCollection values;     // 存放Value的集合
性能排序:

插入性能:LinkedList > Dictionary > HashTable > List

遍历性能:List > LinkedList > Dictionary > HashTable

删除性能:Dictionary > LinkedList > HashTable > List

18. C#中常规容器和泛型容器有什么区别,哪种效率高?

不带泛型的容器需要装箱和拆箱操作速度慢所以泛型容器效率更高数据类型更安全

19. 有哪些常见的数值类?

简单值类型:包括 整数类型、实数类型、字符类型、布尔类型

复合值类型:包括 结构类型、枚举类型

20. C#中委托 和 接口有什么区别?各用在什么场合?

**接口(interface)**是约束类应该具备的功能集合,约束了类应该具备的功能,使类从千变万化的具体逻辑中解脱出来,便于类的管理和扩展,同时又合理解决了类的单继承问题。

C#中的委托 是约束方法集合的一个类,可以便捷的使用委托对这个方法集合进行操作。

在以下情况中使用接口:

1.无法使用继承的场合
2.完全抽象的场合
3.多人协作的场合

以上等等

在以下情况中使用委托:多用于事件处理中

21. C#中unsafe关键字是用来做什么的?什么场合下使用?

非托管代码才需要这个关键字一般用在带指针操作的场合。
项目背包系统的任务装备栏使用到

22. C#中ref和out关键字有什么区别?

ref修饰引用参数。参数必须赋值,带回返回值,又进又出
out修饰输出参数。参数可以不赋值,带回返回值之前必须明确赋值,
引用参数和输出参数不会创建新的存储位置

如果ref参数是值类型,原先的值类型数据,会随着方法里的数据改变而改变,
如果ref参数值引用类型,方法里重新赋值后,原对象堆中数据会改变,如果对引用类型再次创建新对象并赋值给ref参数,引用地址会重新指向新对象堆数据。方法结束后形参和新对象都会消失。实参还是指向原始对象,值不够数据改变了

23. For,foreach,Enumerator.MoveNext的使用,与内存消耗情况

for循环可以通过索引依次进行遍历,foreach和Enumerator.MoveNext通过迭代的方式进行遍历。
内存消耗上本质上并没有太大的区别。
但是在Unity中的Update中,一般不推荐使用foreach 因为会遗留内存垃圾。

24. 函数中多次使用string的+=处理,会产生大量内存垃圾(垃圾碎片),有什么好的方法可以解决。

通过StringBuilder那进行append,这样可以减少内存垃圾

25. 当需要频繁创建使用某个对象时,有什么好的程序设计方案来节省内存?

设计单例模式进行创建对象或者使用对象池

26. JIT和AOT区别

Just-In-Time -实时编译

执行慢安装快占空间小一点

Ahead-Of-Time -预先编译

执行快安装慢占内存占外存大

27. 给定一个存放参数的数组,重新排列数组

void SortArray(Array arr){Array.Sort(arr);}

28. Foreach循环迭代时,若把其中的某个元素删除,程序报错,怎么找到那个元素?以及具体怎么处理这种情况?(注:Try…Catch捕捉异常,发送信息不可行)

foreach不能进行元素的删除,因为迭代器会锁定迭代的集合,解决方法:记录找到索引或者key值,迭代结束后再进行删除。

29. GameObject a=new GameObject() GameObject b=a 实例化出来了A,将A赋给B,现在将B删除,问A还存在吗?

存在,b删除只是将它在栈中的内存删除,而A对象本身是在堆中,所以A还存在

30. C#中 委托和事件的区别

大致来说,委托是一个类,该类内部维护着一个字段,指向一个方法。事件可以被看作一个委托类型的变量,通过事件注册、取消多个委托或方法。

○ 委托就是一个类,也可以实例化,通过委托的构造函数来把方法赋值给委托实例
○ 触发委托有2种方式: 委托实例.Invoke(参数列表),委托实例(参数列表)
○ 事件可以看作是一个委托类型的变量
○ 通过+=为事件注册多个委托实例或多个方法
○ 通过-=为事件注销多个委托实例或多个方法
○ EventHandler就是一个委托

31. 结构体和类有何区别?

结构体是一种值类型,而类是引用类型。(值类型、引用类型是根据数据存储的⻆度来分的)就是值类型用于存储数据的值,引用类型用于存储对实际数据的引用。

那么结构体就是当成值来使用的,类则通过引用来对实际数据操作

32. C#的委托是什么?有何用处?

委托类似于一种安全的指针引用,在使用它时是 当做类来看待而不是一个方法,相当于对一组方 法的列表的引用。

用处:使用委托使程序员可以将方法引用封装在 委托对象内。然后可以将该委托对象传递给可调 用所引用方法的代码,而不必在编译时知道将调 用哪个方法。与C或C++中的函数指针不同,委托 是面向对象,而且是类型安全的。

33. foreach迭代器遍历和for循环遍历的区别

如果集合需要foreach遍历,是否可行,存在一定问题
foreach中的迭代变量item是的只读,不能对其进行修改,比如list.Remove(item)操作
foreach只读的时候记录下来,在对记录做操作,或者直接用for循环遍历
foreach对int[]数组循环已经不产生GC,避免对ArrayList进行遍历

for语句中初始化变量i的作用域,循环体内部可见。
通过索引进行遍历,可以根据索引对所遍历集合进行修改
unity中for循环使用lambda表达式注意闭包问题

foreach遍历原理
任何集合类(Array)对象都有一个GetEnumerator()方法,该方法可以返回一个实现了 IEnumerator接口的对象。
这个返回的IEnumerator对象既不是集合类对象,也不是集合的元素类对象,它是一个独立的类对象。
通过这个实现了 IEnumerator接口对象A,可以遍历访问集合类对象中的每一个元素对象
对象A访问MoveNext方法,方法为真,就可以访问Current方法,读取到集合的元素。

  List<string> list = new List<string>() { "25", "哈3", "26", "花朵" };
               IEnumerator listEnumerator = list.GetEnumerator();
        while (listEnumerator.MoveNext())
        {
            Console.WriteLine(listEnumerator.Current);
        }

34. C#和C++的区别?

简单的说:C# 与C++ 比较的话,最重要的特性 就是C# 是一种完全面向对象的语言,而C++ 不 是,另外C# 是基于IL 中间语言
和.NET Framework CLR 的,在可移植性,可维 护性和强壮性都比C++ 有很大的改进。C# 的设 计目标是用来开发快速稳定可扩展的应用程序, 当然也可以通过Interop和Pinvoke 完成一些底层操作

具体对比

1.继承:C++支持多继承,C#类只能继承一个基类中的实现但可以实现多个接口。

2.数组:声明 C# 数组和声明 C++ 数组的语法不同。在 C# 中,“[]”标记出现在数组类型的后面。

3.数据类型:在C++中bool类可以与整型转换,但C#中bool 类型和其他类型(特别是 int)之间没有转换。long 类型:在 C# 中,long 数据类型为 64 位,而在 C++ 中为 32 位。

4.struct 类型:在 C# 中,类和结构在语义上不同。struct 是值类型,而 class 是引用类型。

5.switch 语句:与 C++ 中的 switch 语句不同,C# 不支持从一个 case 标签贯穿到另一个 case 标签。

6.delegate 类型:委托与 C++ 中的函数指针基本相似,但前者具有类型安全,是安全的。

7.从派生类调用重写基类成员。base

8.使用 new 修饰符显式隐藏继承成员。

9.重写方法需要父类方法中用virtual声名,子类方法用override 关键字。

10.预处理器指令用于条件编译。C# 中不使用头文件。C# 预处理器指令

11.异常处理:C#中引入了 finally 语句,这是C++没有的。

12.C# 运算符:C# 支持其他运算符,如 is 和 typeof。它还引入了某些逻辑运算符的不同功能。

13.static 的使用,static方法只能由类名调用,改变static变量。

14.在构造基类上替代 C++ 初始化列表的方法。

15.Main 方法和 C++ 及Java中的 main 函数的声明方式不同,Main而不能用main

16.方法参数:C# 支持 ref 和 out 参数,这两个参数取代指针通过引用传递参数。

17.在 C# 中只能在unsafe不安全模式下才使用指针。

18.在 C# 中以不同的方式执行重载运算符。

19.字符串:C# 字符串不同于 C++ 字符串。

20.foreach:C#從VB中引入了foreach关键字使得以循环访问数组和集合。

21.C# 中没有全局方法和全局变量:方法和变量必须包含在类型声明(如 class 或 struct)中。

22.C# 中没有头文件和 #include 指令:using 指令用于引用其他未完全限定类型名的命名空间中的类型。

23.C# 中的局部变量在初始化前不能使用。

24.析构函数:在 C# 中,不能控制析构函数的调用时间,原因是析构函数由垃圾回收器自动调用。析构函数

25.构造函数:与 C++ 类似,如果在 C# 中没有提供类构造函数,则为您自动生成默认构造函数。该默认构造函数将所有字段初始化为它们的默认值。

26.在 C# 中,方法参数不能有默认值。如果要获得同样的效果,需使用方法重载。

35. C#引用和C++指针的区别

C#不支持指针,但可以使用Unsafe,不安全模式,CLR不检测
C#可以定义指针的类型、整数型、实数型、struct结构体
C#指针操作符、C#指针定义
使用fixed,可以操作类中的值类型
相同点:都是地址
指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。

不同点
指针是个实体,引用是个别名。
sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;
引用是类型安全的,而指针在不安全模式下

36. 堆和栈的区别?

通常保存着我们代码执行的步骤,如在代码段1中 AddFive()方法,int pValue变量,int result变量等等。而堆上存放的则多是对象,数据等。(译者注:忽略编 译器优化)我们可以把栈想象成一个接着一个叠放在 一起的盒子。当我们使用的时候,每次从最顶部取走 一个盒子。栈也是如此,当一个方法(或类型)被调 用完成的时候,就从栈顶取走(called a Frame,译 注:调用帧),接着下一个。堆则不然,像是一个仓 库,储存着我们使用的各种对象等信息,跟栈不同的 是他们被调用完毕不会立即被清理掉。

37. Heap与Stack有何区别?

1.heap是堆,stack是栈。

2.stack的空间由操作系统自 动分配和释放,heap的空间是手动申请和释放的, heap常用new关键字来分配。

3.stack空间有限,heap 的空间是很大的自由区。

38. Mock和Stub有何区别?

Mo

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值