C#经典面试题总结
一、值类型与引用类型的区别
值类型:(1)简单类型
有符号类型:sbyte、short、int、long
无符号整型:byte、ushort、uint、ulong
Unicode字符:char
IEEE浮点型:float、double
高精度小数:decimal
布尔型:bool
(2)枚举类型:用户自定义类型:enum
(3)结构类型:用户自定义类型:struct
引用类型:(1)类类型
所有其他类型的最终基类:object
Unicode字符串:string
用户自定义类型:class
(2)接口类型:用户自定义类型:interface
(3)数组类型:单维与多维数组,例如:int[]和int[,]
(4)委托类型:用户自定义类型:delegate
二、内存结构
值类型和引用类型最根源的区别就是其内存分配的差异,在这之前首先要理解CLR的内存中两个重要的概念:
(1)Stack栈:线程栈,由操作系统管理,存放值类型、引用类型变量(就是引用对象在托管堆上的地址)。栈是基于线程的,也就是说一个线程会包含一个线程栈,线程栈中的值类型在对象作用域结束后会被清理,效率很高。
(2)GC Heap托管堆:进程初始化后在进程地址空间上划分的内存空间,存储.NET运行过程中的对象,所有的引用类型都分配在托管堆上,托管堆上分配的对象是由GC来管理和释放的。托管堆是基于进程的,当然托管堆内部还有其他更为复杂的结构。
问题:
(1)值类型一直都存储在栈上面吗?所有的引用类型都存储在托管堆上面吗?
1.单独的值类型变量,如局部值类型变量都是存储在栈上面的;
2.当值类型是自定义class的一个字段、属性时,它随引用类型存储在托管堆上,此时它是引用类型的一部分;
3.所有的引用类型肯定都是存在托管堆上的。
4.还有一种情况,结构体(值类型)中定义引用类型字段,结构体是存储在栈上,其引用变量字段只存储内存地址,指向堆中的引用实例。
三、参数-按值传递与引用传递的区别
按值传递
(1)对于值类型(int a):传递的是变量a的值拷贝副本,因此原本的a值并没有改变。
(2)对于引用类型(User user);传递的是变量user的引用地址(User对象实例的内存地址)拷贝副本,因此他们操作都是同一个User对象实例。
按引用传递
按引用传递的两个主要关键字:out和ref不管值类型还是引用类型,按引用传递的效果是一样的,都不传递值副本,而是引用的引用(类似c++的指针的指针)。
out和ref告诉编译器方法传递的是参数地址,而不是参数本身。
out和ref的主要异同:
1.out和ref都表示编译器传递参数地址,在行为上是相同的;
2.它们的使用机制稍有不同,ref要求参数在使用之前要显示初始化,out要在方法内部初始化;
3.out和ref不可以重载,就是不能定义Method(ref int a)和Method(out int a)这样的重载,从编译角度看,二者的实质是相同的,只是使用时有区别;