C#面试题

Posted 积少成多

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#面试题相关的知识,希望对你有一定的参考价值。

值类型与引用类型:

1.值类型和引用类型的区别?

值类型包括简单类型、结构体类型和枚举类型,引用类型包括自定义类、数组、接口、委托等。
1、赋值方式:将一个值类型变量赋给另一个值类型变量时,将复制包含的值。这与引用类型变量的赋值不同,引用类型变量的赋值只复制对象的引用(即内存地址,类似C++中的指针),而不复制对象本身。
2、继承:值类型不可能派生出新的类型,所有的值类型均隐式派生自 System.ValueType。但与引用类型相同的是,结构也可以实现接口。
3、null:与引用类型不同,值类型不可能包含 null 值。然而,可空类型功能允许将 null 赋给值类型。
4、每种值类型均有一个隐式的默认构造函数来初始化该类型的默认值,值类型初始会默认为0,引用类型默认为null。
5、值类型存储在栈中,引用类型存储在托管堆中。

2. 结构和类的区别?

结构体是值类型,类是引用类型,主要区别如题1。其他的区别:
结构不支持无惨构造函数,不支持析构函数,并且不能有protected修饰;
结构常用于数据存储,类class多用于行为;
class需要用new关键字实例化对象,struct可以不适用new关键字;
class可以为抽象类,struct不支持抽象;

3. delegate是引用类型还是值类型?enum、int[]和string呢?

enum枚举是值类型,其他都是引用类型。

4. 堆和栈的区别?

线程堆栈:简称栈 Stack
托管堆: 简称堆 Heap
值类型大多分配在栈上,引用类型都分配在堆上;
栈由操作系统管理,栈上的变量在其作用域完成后就被释放,效率较高,但空间有限。堆受CLR的GC控制;
栈是基于线程的,每个线程都有自己的线程栈,初始大小为1M。堆是基于进程的,一个进程分配一个堆,堆的大小由GC根据运行情况动态控制;

5.“结构”对象可能分配在堆上吗?什么情况下会发生,有什么需要注意的吗?

结构是值类型,有两种情况会分配在对上面:
结构作为class的一个字段或属性,会随class一起分配在堆上面;
装箱后会在堆中存储,尽量避免值类型的装箱,值类型的拆箱和装箱都有性能损失,下一篇会重点关注;

6. 理解参数按值传递?以及按引用传递?

按值传递:对于值类型传递的它的值拷贝副本,而引用类型传递的是引用变量的内存地址,他们还是指向的同一个对象。
按引用传递:通过关键字out和ref传递参数的内存地址,值类型和引用类型的效果是相同的。

7. out 和 ref的区别与相同点?

out 和 ref都指示编译器传递参数地址,在行为上是相同的;
他们的使用机制稍有不同,ref要求参数在使用之前要显式初始化,out要在方法内部初始化;
out 和 ref不可以重载,就是不能定义Method(ref int a)和Method(out int a)这样的重载,从编译角度看,二者的实质是相同的,只是使用时有区别;

8. 有几种方法可以判定值类型和引用类型?

简单来说,继承自System.ValueType的是值类型,反之是引用类型。

9. C#支持哪几个预定义的值类型?C#支持哪些预定义的引用类型?

值类型:整数、浮点数、字符、bool和decimal
引用类型:Object,String

10. 说说值类型和引用类型的生命周期?

值类型在作用域结束后释放。
引用类型由GC垃圾回收期回收。这个答案可能太简单了,更详细的答案在后面的文章会说到。

12. 如果结构体中定义引用类型,对象在内存中是如何存储的?例如下面结构体中的class类 User对象是存储在栈上,还是堆上?
public struct MyStruct
{
public int Index;
public User User;
}
MyStruct存储在栈中,其字段User的实例存储在堆中,MyStruct.User字段存储指向User对象的内存地址。

 

装箱与拆箱

1.什么是拆箱和装箱?

装箱就是值类型转换为引用类型,拆箱就是引用类型(被装箱的对象)转换为值类型。

2.什么是箱子?

就是引用类型对象。

3.箱子放在哪里?

托管堆上。

4.装箱和拆箱有什么性能影响?

装箱和拆箱都涉及到内存的分配和对象的创建,有较大的性能影响。

5.如何避免隐身装箱?

编码中,多使用泛型、显示装箱。

6.箱子的基本结构?

上面说了,箱子就是一个引用类型对象,因此她的结构,主要包含两部分:
值类型字段值;
引用类型的标准配置,引用对象的额外空间:TypeHandle和同步索引块,关于这两个概念在本系列后面的文章会深入探讨。

7.装箱的过程?

1.在堆中申请内存,内存大小为值类型的大小,再加上额外固定空间(引用类型的标配:TypeHandle和同步索引块);
2.将值类型的字段值(x=1023)拷贝新分配的内存中;
3.返回新引用对象的地址(给引用变量object o)

8.拆箱的过程?

1.检查实例对象(object o)是否有效,如是否为null,其装箱的类型与拆箱的类型(int)是否一致,如检测不合法,抛出异常;
2.指针返回,就是获取装箱对象(object o)中值类型字段值的地址;
3.字段拷贝,把装箱对象(object o)中值类型字段值拷贝到栈上,意思就是创建一个新的值类型变量来存储拆箱后的值;

 

string与字符串操作

1.字符串是引用类型类型还是值类型?

引用类型。

2.在字符串连加处理中,最好采用什么方式,理由是什么?

少量字符串连接,使用String.Concat,大量字符串使用StringBuilder,因为StringBuilder的性能更好,如果string的话会创建大量字符串对象。

3.使用 StringBuilder时,需要注意些什么问题?

少量字符串时,尽量不要用,StringBuilder本身是有一定性能开销的;
大量字符串连接使用StringBuilder时,应该设置一个合适的容量;

以上是关于C#面试题的主要内容,如果未能解决你的问题,请参考以下文章

C#刷遍Leetcode面试题系列连载:No.593 - 有效的正方形

C#面试题

C#面试题伪代码

C#常见算法面试题小结

C#面试题

C# 面试题