1 什么是.NET?什么是CLI?什么是CLR?IL是什么?JIT是什么?它是如何工作的?GC是什么?简述一下GC的工作方式?
.net的全称是.NET Framework 是一种托管代码的编程模型,采用系统虚拟机运行的编程平台以通用语言运行库(CommonLanguageRuntime)为基础支持多种语言翻译为机器码用于执行。
CLI(Common Language Infrasttuctrue)是CLR的一个子集,也就是Net中最终对编译成MSIL代码的应用程序的运行环境进行管理的那一部分。在CLR结构图中CLI位于下半部分,主要包括类加载器(Class Loader),实时编译器(IL To Native Compilers)和一个运行时环境的垃圾收集器(Garbage Collector)
CLR(Common Language Runtime)是一个刻有多种编程语言使用的运行时,CLR的核心功能(比如内存管理,程序集加载,安全性,异常处理和线程同步)可由面向CLR的所有语言使用,源代码文件通过CLR的编译器将生成四个部分,即PE32或PE32+的头,CLR的头(包括CLR的版本,标记托管模块入口方法),元数据(a 描述源代码中定义的类型和成员 b 描述源代码中引用的类型和成员),以及IL(中间语言),之后CLR将IL编译成CPU指令。PS C++允许编写非托管类型。
JIT(CLR中的一种编译器(JIT[just in time]))在JITCompiler中 1 在负责实现类型的程序集的元数据中查找被调用的方法 2 从元数据中获取该方法的IL 3 分配内存块 4 将IL编译成本地的CPU指令,然后将这些本地代码存储到步骤3分配的内存中5 在Type表中修改与方法对应的记录项,使它只想步骤3分配的内存块 6 跳转到内存块中的本地代码
GC(在托管对分配一个对象时候,可能强制执行一次GC)
2 类和结构的区别是什么?它们对性能有影响么?.NET BCL里有哪些是类(结构),为什么他们不是结构(类)?在定义类型时,您是如何选择类还是结构?
答:结构是值类型而类是引用类型,因为引用类型总是被托管堆分配,则肯定存在以下实时1 内存必须从托管堆分配 2 堆内存分配的每个对象都有一些额外成员,这些成员必须初始化 3 对象的其他字节总是设为0 4 从托管堆分配一个对象时,可能强制一次GC 所以使用值类型和引用类型,对性能影响较大。 BCL中 从System.ValueType派生的int32 bool Decimal TimeSpan DayofWeek 等都是值类型,而其他的类型则是引用类型。有一个原因Int32 Bool等是值类型是因为他们使用较频繁,不需要有堆来分配内存,并在堆存入引入指针地址和索引列表。
3 在.NET 程序运行中,什么是堆,什么是栈?什么情况下会在堆(栈)上分配数据?他们有性能上的区别么?“结构”对象可能分配在堆吗?什么情况下会发生,有什么需要注意的吗?
答:堆的全称是托管堆,而每一个线程创建的时候都将分配一个线程栈,这个栈的空间用于向方法传递实参,并用于方法内部定义局部变量.声明一个变量,类型或者字段的时候会在栈上分配数据,之后通过c#的构造器可以分配堆的数据。性能的影响有一部分体现在GC方面,及在堆上的数据,会通过c#的GC算法(CheckCompress),之后通过代的方式对堆上很久没有使用的内存进行释放。“结构对象”可以在堆上分配内存,这个过程叫做Box 装箱,装箱的过程可以描述为 1 在托管堆中分配好内存。分配的内存量是值类型的各个字段需要的内存量加上托管堆的所有对象都有的两个额外成员(类型对象指针和同步索引块)需要的内存量。 2 值类型的字段复制到新分配的堆内存 3 返回对象的地址。现在,这个地址是对一个对象的引用,值类型现在是一个引用类型(而拆箱的过程就是获取对象指针) 在比如说ArrayList.Add(object value)的类似情况下会发生装箱。(通过ILDasm.exe)来观察代码注意事项
Int32 v =5;
object o = v; --1 对v进行装箱 将引用指针存储到 o
v=123;
Console.WriteLine(v+","+(Int32)o); --在这个方法里会2次装箱操作 1 对v 进行装箱,并将指针保留到栈上以进行concat(链接操作) 将字符串加载栈上以执行Contact操作 将字符串加载到栈上执行concat操作 对o进行拆箱,获取一个指针,他指向栈上Int32片段 对Int32进行装箱,并将指针保留在栈上进行Concat操作。
如果需要对值类型的实例引用,该实例就必须装箱。将一个值类型的实例传给需要获取一个引用类型的方法,就会发生这种情况。虽然未装箱的值类型没有类型对象指针,但仍可调用由类型类型继承或重写的虚方法,如果没有调用基类的实现,那么就不会装箱,但是如果调用了积累的实现,则被装箱。而GetType或者MemberwiseClone ,都会对值类型进行装箱。
4 异常的作用是什么? .NET BCL中有哪些常见的异常?在代码中您是如何捕获/处理异常的?在catch(ex)中,“throw”和“throw ex”有什么区别?您会如何设计异常结构,什么情况下您会抛出异常?
异常是系统容错和规范程序的不可或缺的重要因素和手段。
BCL中常见的异常有StackOverflowException、OutOfMemoryException、NullReferenceException、IndexOutOfRangeException、ArgumentException、DivideByZeroException等;
捕获异常使用try-catch-finally语句块 ;
"throw"和"throw ex"的区别是:推荐使用throw来抛出异常,因为throw ex会将上次异常清空,又抛出一个新的异常,不利于堆栈跟踪错误源头。
5 List和T[]的区别是什么,平时你是如何选择的?Dictionary<TKey,TValue>是做什么的?.NET BVL中还有哪些常用的容器?他们分别是如何实现的(哪种数据结构)?分别适用于哪些场景?
List<T>长度不固定,动态变化,支持方法较多;T[]固定大小的泛型数组。
Dictionary<TKey, TValue>是泛型字典,提供一对一的关系;
.Net BCL中常用的集合有Stack<T>、Queue<T>、LinkedList<T>,对应的数据结构是栈、队列和链表。
6 抽象类和接口有什么区别?使用时有什么需要注意的么?如何选择是定义一个“完全抽象”的抽象类,还是接口?什么是接口的“显式实现”?为什么说它很重要?
答:相同点:都不能被实例化,都可以通过继承实现其抽象方法;
不同点:接口支持多继承,抽象类不能;接口只能定义行为,抽象类既可以定义行为,还能提供实现;接口只包含方法、属 性、索引器和事件的签名,不能包括自定义字段和实现方法,抽象类可以包含自定义字段和实现方法。
7 字符串是引用类型还是结构类型?他和普通的应用类型相比有什么特别的地方么?使用字符串时有什么需要注意的地方?为什么说StringBuilder比较高效?在链接字符串时,他无论何时都比直接相加更高效么?
字符串是特殊的引用类型。
其特殊之处在于string是不可变的,即字符串恒定性(Immutability),字符串一经创建,就不可改变。
当大量使用string进行拼接的时候,直接使用string+会影响效率,使用StringBuilder更为合适;
不是的,对于简单的字符串连接操作,在性能上StringBuilder不一定总是优于String,因为StringBuilder对象的创 建代价比较大,在字符串连接目标较少的情况下,过度滥用StringBuilder会导致性能的浪费而非节约。只有大量的或者无法预知次数的字符串操作,才考虑以StringBuilder实现。
8 如何高效的进行数组复制?“二维数组和数组内数组有什么区别”?在使用双重循环遍历一个二维数组时,如何选择内外层的遍历顺序?
9 什么是元编程,.NET有哪些元编程的手段和场景?什么是反射?能否举一些反射的常用场景?有人说反射性能较差,您怎么看待这个问题?有什么办法可以提高反射的性能么?
元编程是对程序本身的编程,如反射;
程序集包含模块,模块又包含类型,类型下有成员,反射就是管理程序集、模块、类型的对象,它能够动态的创建类,获 取现有对象的类型,能调用类型的方法和访问类型的字段属性。它是在程序运行时创建和使用类型的。
10 委托是什么?匿名方法是什么?在C#3.0 中 lambda表达式是什么?扩展方法是什么?LINQ是什么?您觉得在C#3.0中还有哪些重要的特性,他们带来什么优势?BCL中哪些类库和这些特性有关?您平时工作最常用哪些?
委托是指向函数的指针;匿名方法类似javascript中的匿名方法,无须声明,直接使用;
Lambda表达式函数式编程,LINQ表示语言集成查询,为CLR提供了信息查询能力。
扩展方法,用this关键字标记扩展方法的第一个参数,且该参数不能为指针类型。
.Net 面试题目尝试回答