龙空技术网

Unity面试题加强版之一C#语言部分

萌芽成树 204

前言:

眼前你们对“net中ref和out的用法”大概比较着重,朋友们都想要学习一些“net中ref和out的用法”的相关知识。那么小编同时在网络上汇集了一些对于“net中ref和out的用法””的相关文章,希望兄弟们能喜欢,小伙伴们快快来学习一下吧!

## Unity面试题加强版之一C#语言部分

***unity超全面试题,掌握轻轻松松拿Offer,码住学习***

**1.重载和重写的区别**

1)所处位置不同 重载在同类中 重写在父子类中

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

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

4)多态时机不同 重载时编译时多态 重写是运行时多态

**2.面向对象的三大特点**

封装、继承、多态

1.继承: 提高代码重用度,增强软件可维护性的重要手段,符合开闭原则。

2.封装: 封装是将数据和行为相结合,通过行为约束代码修改数据的程度,增强数据的安全性,属性是C#封装实现的最好体现。

3.多态性: 多态性是指同名的方法在不同环境下,自适应地反应出不同的表现,是方法动态展示的重要手段。

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

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

是堆中存放的地址。

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

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

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

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

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

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

private:仅对该类公开

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

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

protected internal:protected + internal

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

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

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

****6.请简述 ArrayList 和 List<Int>的主要区别****

ArrayList 不带泛型 数据类型丢失

List<T> 带泛型 数据类型不丢失

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

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

避免:

1)减少 new 产生对象的次数

2)使用公用的对象(静态成员)

3)将 String 换为 StringBuilder

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

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

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

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

**9.下列代码在运行中会产生几个临时对象?**

![在这里插入图片描述]()

其实在 C#中第一行是会出错的(Java 中倒是可行)。应该这样初始化:

string b = new string(new char[]{'a','b','c'});

忽略错误的话:

1."abc"

2.a.ToUpper()

3."123"

4.a.ToUpper()+"123"

**10.下列代码在运行中会发生什么问题?如何避免?**

```csharp

List<int>ls=new List<int>(new int[]{1,2,3,4,5});

foreach (int item in ls){

Console.WriteLine(item*item);

ls.Remove(item);

}

```

会产生运行时错误,因为 foreach 是只读的。不能一边遍历一边修改。

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

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

**12.反射地实现原理?**

可以在加载程序运行时,动态获取和加载程序集,并且可以获取到程序集的信息

反射即在运行期动态获取类、对象、方法、对象数据等的一种重要手段

主要使用的类库:System.Reflection

核心类:

1.Assembly描述了程序集

2.Type描述了类这种类型

3.ConstructorInfo描述了构造函数

4.MethodInfo描述了所有的方法

5.FieldInfo描述了类的字段

6.PropertyInfo描述类的属性

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

**13. .Net 与 Mono 的关系?**

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

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

构造函数格式为 public+类名如果加上 static 会报错(静态构造函数不能有访问修饰符)

原因:静态构造函数不允许访问修饰符,也不接受任何参数;无论创建多少类型的对象,静态构造函数只执行一次;运行库创建类实例或者首次访问静态成员之前,运行库调用静态构造函数;静态构造函数执行先于任何实例级别的构造函数;显然也就无法使用 this 和 base 来调用构造函数。

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

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

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

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

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

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

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

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

StringBuilder 可变,非线程同步。

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

(a,b) => {};

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

```csharp

public int CountNumber(int num) {

if (num == 1 || num == 2) {

return 1;

} else {

return CountNumber(num -1) + CountNumber(num-2);

}

}

```

**18.冒泡排序(手写代码)**

```csharp

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;

}

}

}

}

```

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

List,HashTable,Dictionary,Stack,Queue

List:索引泛型容器 访问速度快 修改速度慢

HashTable/Dictionary:散列表格式 查询效率高 空间占用较大

Stack:后进先出

Queue: 先进先出

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

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

**21.有哪些常见的数值类?**

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

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

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

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

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

在以下情况中使用接口:

1.无法使用继承的场合

2.完全抽象的场合

3.多人协作的场合

以上等等

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

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

非托管代码才需要这个关键字 一般用在带指针操作的场合

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

ref修饰参数,表示进行引用传递,out修饰参数也表示进行引用传递,但传递的引用只为带回返回值 ref又进又出 out不进只出

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

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

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

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

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

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

**28.JIT 和AOT区别**

Just-In-Time - 实时编译

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

Ahead-Of-Time - 预先编译

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

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

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

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

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

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

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

**32.你拥有A块钱,一瓶水B块钱,每瓶水可以得到一个瓶盖,每C个瓶盖可以换一瓶水请写出函数求解上面题目,上面题目ABC为参数**

```csharp

public static int Buy(int a,int b,int c) {

return a/b + ForCap(c,a/b);

}

public static int ForCap(int c,int d) {

if (d<c) {

return 0;

} else {

return d/c + ForCap(c,d/c + d%c);

}

}

```

**33.有一排开关,第一个人把所有的开关打开,第二个人按2的倍数的开关,第三个人按3的倍数的开关,以此类推,现在又n个开关,k个人,写函数求最后等两者的开关,输入参数n和k**

```csharp

static void Main(string[] args) {

int n = int.Parse(Console.ReadLine());

int k = int.Parse(Console.ReadLine());

Function(100,100);

}

static void Function(int n, int k) {

int i, j = 0;

bool[] a = new bool[1000]; //初始false:关灯,true:开灯

for (i = 1; i <= k; i++) //k个人

for (j = 1; j <= n; j++) //n个灯

if (j % i == 0)

a[j] = !a[j]; //取反,false变true,原来开变关,关变开

for (i = 1; i <= n; i++) //最后输出a[i]的值就可以了

if (a[i]) //灯亮着

Console.WriteLine(i);

}

```

34.数值转换,将任意整数转换成8进制形式

```csharp

static void Main(string[] args) {

int n;

n =int.Parse(Console.ReadLine());

Console.WriteLine("输入的10进制为:{0}",n);

Console.Write("转换为8进制数为: ");

d2o(n);

}

static void d2o(int n) {

if (n > 7) {

d2o(n / 8);

}

Console.Write(n%8);

}

```

**35.找出200以内的素数。**

```csharp

static void Main(string[] args) {

int count = 0;

for (int i = 1; i < 200; i++) { //外层循环:要判断的数

for (int j = 2; j <=i; j++){

if (i % j == 0&& i!=j) {

break;

}

if (j == i ) { //结束的条件:最后一个数还没有被整除

count++;

Console.WriteLine(i);

}

}

}

Console.WriteLine(count);

}

```

**36.打印杨辉三角形**

```csharp

public static void YHSJ(){

int [][]a= new int[7][] ;

a[0] = new int[1]; //a[0][0]=1;

a[1] = new int[2] ;

for (int i = 0; i < 7; i++) {

a[i] = new int[i+1] ;

a[i][0] =1;

a[i][i]=1;

if(i>1) { //求出中间的数据

for(int j=1;j<i; j++){

a[i][j]= a[i-1][j-1]+a[i-1][j];

}

}

}

for (int i=0; i<a.Length; i++) {

for (int k = 0; k < a.Length-1-i; k++) {

Console.Write("");

}

for(int j=0;j<a[i].Length; j++ ) {

Console.Write(a[i][j] + "");

}

Console.WriteLine();

}

}

```

**37.中国有句俗话“三天打鱼两天晒网”,某人从2000年1月1日起开始“三天打鱼两天晒网”,问这个人在今后的某天中“打鱼”还是”晒网**”

```csharp

public static void Compute(){

Console.WriteLine ((DateTime.Now - DateTime.Parse("2000-01-01")).Days%5<3?"打鱼":"晒网");

}

```

**38.假设当前市场价一只鸡10元,一只鸭12元5角。请写一个函数ShowPrice,输入参数分别为鸡和鸭的个数(非负整型),功能为显示出总价钱,精确到分。例如调用ShowPrice(5,10)后输出175.00。请注意程序的可读性和易于维护性。**

```csharp

static void ShowPrice(int num_chicken, int num_duck) {

float totalPrice = 0.00f;

float price_chicken = 10f;

float price_duck = 12.5f;

totalPrice = num_chicken * price_chicken + num_duck * price_duck;

Console.WriteLine("总价钱为:{0:0.00}", totalPrice);

}

```

**39.请写一个函数,用于返回n!(阶乘)结果末尾连续0的个数,如GetZeroCount(5)返回1,因为5! = 120,末尾连续1个0**

```csharp

static void Main(string[] args) {

int fac = Factorial(5);

Console.WriteLine(CountZero(fac));

}

public static int Factorial(int n) {

if (n == 1) {

return 1;

} else {

return n * jiecheng(n - 1);

}

}

//求连续的0的个数

public static int CountZero(int num) {

int result = 0; // 最后的结果

String numStr = num.ToString();

for (int i = numStr.Length - 1; i >= 0; i--) {

if (numStr[i] == '0') {

result ++;

} else {

break;

}

}

return result;

}

```

标签: #net中ref和out的用法