以前一直是被别人面试,后来“多年的媳妇熬成婆”,走上技术管理岗位之后也面试过别人。对于面试我始终认为有些技巧的,想要在短短半个小时到一两个小时内了解候选人是否满足岗位需要,确实不太容易。
我一般会根据面试者的工作经验状况选择相应的面试形式。对于工作经验较少的面试者(两年及以下)偏向于做题或者实际上机操作为主,因为这样的面试者进来之后也是做一些初级的工作,能够熟练操作软件和了解一些基本常识就够了;如果具有多年工作经验的一般都是通过谈话来了解面试者的水平,俗话说“行家一伸手,便知有没有”,经验丰富的开发人员知道在不同的场合下、不同的阶段要注意些什么问题,通过谈话就能知道对方处在什么水平。
上面说的是本人的经验,下面也谈谈本人几年来在电话面试中被问及的一些有代表性的问题,这些问题多半与.NET有关,如果有兴趣可以看一看。当然在这些我认为值得记录的问题当中绝对没有任何有关控件用法的问题。下面的问题以我回忆的次序为序。
问:请谈一谈ASP.NET1.1和ASP.NET2.0中页面的不同点。
下面请看在ASP.NET1.1中采用页面代码分离模式时ASP.NET页面的声明代码(来自于彬月论坛,我早年曾经以它来学习三层架构):
- <%@ Page language="c#" Codebehind="ListLWord.aspx.cs" AutoEventWireup="false" Inherits="TraceLWord1.ListLWord" %>
它对应的后台代码声明如下:
- public class ListLWord : System.Web.UI.Page
而在ASP.NET2.0中采用页面代码分离模式时的ASP.NET页面代码:
- <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Test.aspx.cs" Inherits="Test" %>
它对应的后台代码如下:
- public partial class Test : System.Web.UI.Page
从代码声明上可以看出ASP.NET1.1中ASP.NET页面HTML代码与cs代码建立关联是通过Codebehind关键字,在后台代码中它是直接继承System.Web.UI.Page的;而在ASP.NET2.0中是通过CodeFile关键字建立关联的,在后台代码中使用了partial关键字,表明当前类是一个局部类。
因为年代比较久远,加之ASP.NET1.1基本没有人在使用,对这两种方式的处理方式的不同我已经记得不太清楚了,记得好像当年有个人专门讲了这种处理方式的优点的。这里要说的是,ASP.NET引擎在背后做的一些工作。Java EE的程序员都会被告知所有的JSP页面在第一次被请求时会被编译成servlet文件,然后再将这些servler文件编译成.class文件文件,以后再次请求的时候就直接运行编译后的.class文件(我当年学JSP的时候别人是这么告诉我的),其实在ASP.NET中也存在着类似的处理流程,并且因为在ASP.NET中处理过程比这个还稍微复杂一点(特别是在使用了代码分离模式时),当第一次请求时编译引擎会将包含HTML代码的aspx页面代码和包含cs代码的.cs文件合成一个.cs文件,然后再将这个.cs文件编译成.dll文件,JIT(即时编译器)会将这些代码编译成本地机器代码,然后运行这些本地机器代码得到的结果返回给客户端,这些本地机器代码会缓存在内存当中,如果在内存没有被清理的情况下再有客户端请求这个页面就会直接运行内存中缓存的本地机器代码,否则就需要再将.dll文件编译成本地机器代码并执行和缓存了。当然,如果对aspx代码或者.cs代码进行了改动,那么下一次请求就会又走一遍整个流程了。
问:请谈一谈二进制序列化和Xml序列化的特点。
二进制序列化和反序列化使用BinaryFormatter类,Xml序列化使用XmlSerializer类。二进制序列化的特点是:无论是否是只读属性,所有成员都将被序列化;序列化的性能高。Xml序列化的特点是:互操作性强;可读性强。
其实关于序列化的类还有SoapFormatter等其它序列化方式,适用于不同的场合。在周公博客上也有关于BinaryFormatter、XmlSerializer和SoapFormatter用法的例子,有兴趣的可以找一找。
问:什么是浅拷贝?什么是深层拷贝?如何实现深层拷贝?
浅拷贝(shallow copy)也叫影子拷贝,在.NET里所有对象的老祖宗Object类里就定义了一个MemberwiseClone()方法来实现浅拷贝。具体做法是创建一个浅表副本,方法是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。 如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。
在浅拷贝里会出现一个问题,那就是如果对对象A实行浅拷贝得到对象B,假设对象A中有引用类型变量M,一旦改变了M的值对象B中对应的变量值也会随之改变,这在有些情况下会产生不可预知的情况,为了解决这个问题,就需要实现深层拷贝(deep copy)。实行深层拷贝之后,不管是A中值类型变量的值被复制到B中,连A中引用类型的字段的值也会被复制到B中,这样改变A中引用类型的值就不会反应到B中对应的字段上去。
如何实现深层拷贝呢?在MSDN中建议我们实现ICloneable来达到实现创建深层副本或者浅表副本的目的,在实际中一般都是采用序列化A,然后将序列化的结果反序列化得到B来实现深层拷贝的目的。
问:请讲一讲ASP.NET命名管道的细节。
ASP.NET命名管道也叫HTTP Pipeline,它是指当客户端的请求经Web服务器到ASP.NET引擎之后的一系列处理过程的细节。关于HTTP流程处理细节在周公拙作《ASP.NET夜话》第十二章中描述过(因为和出版社签订了协议所以没有在博客上发表),如果有想知道细节的请看http://www.cnblogs.com/xiaopin/archive/2010/08/26/1808956.html了解,特别是那些只知道拖拽控件的程序员朋友强烈建议去看一看,看过那个图之后你就会知道原来你随便在网页上拖拽一个控件,这么简单的过程背后却有很多复杂的事情要处理,在其中涉及到了HttpApplication、HttpContext、HttpResponse、HttpRequest、HttpCookie、HttpSession还有HttpSessionState等,除此之外还应该了解一下ASP.NET页面的生命周期,这样你就知道在什么时候可以做什么不可以做什么。
在这里仅仅将作者话的那个图拿出来在这里展示一下,这个图画得相当不错。
问:请问ASP.NET在IIS5、IIS6和IIS7中会有什么不同。
IIS5的ASP.NET请求处理过程
从上图可以看出在IIS中Web服务器和ASP.NET程序分开,Web服务器进程是一个名为inetinfo.exe的非托管程序,而ASP.NET程序进程是一个名为aspnet_wp.exe的进程。
IIS6的ASP.NET请求处理过程
从上图可以看出在IIS6中监听客户端HTTP请求的是http.sys,它在kernel-mode下工作,而处理ASP.NET请求的则是w3wp.exe,它是工作在user-mode下,而在kernel-mode下工作的允许访问所有内存和CPU指令。
IIS7的ASP.NET请求处理过程
在IIS7中处理模式又可以分为两种:经典模式和集成模式。在IIS7中经典模式是兼容IIS6的模式,在IIS6中ASP.NET ISAPI是以插件的形式存在,而在IIS7中则是从插件的角色转换到核心。
IIS6 的执行架构图,以及 IIS7 应用程序池配置成经典模式的执行架构图
IIS 7 的执行架构图(集成托管信道模式下的架构)
也就是从IIS5到IIS6的改进主要在http.sys上,而从IIS6到IIS7的改进主要是ISAPI的改进。
注:上面文字和图片来自于对蝈蝈俊.net文章的整理,该篇文章的网址是:http://blog.joycode.com/ghj/archive/2008/07/25/115200.joy
问:请问System.Web.UI.Page类实现了哪个接口?它有定义了哪些方法和属性?
我们知道所有的ASP.NET页面都直接或者间接集成自System.Web.UI.Page类,System.Web.UI.Page类又实现了System.Web.IHttpHandler接口,在这个接口中定义了一个void ProcessRequest(HttpContext context)方法和一个IsReusable属性。IsReusable属性是一个bool值,这个值是指示IHttpHandler的实例是否可再次使用,一般情况下这个值应该设为false,典型的例子就是我们自己编写的Page类,因为它默认设置为false了,所以即使想服务器上同一个页面发送了多次请求,每次得到的都是不同实例。很多初学者经常问:明明我在Page内声明了一个成员变量并赋值了,为什么点击一个按钮PostBack之后就没有值了呢?就是因为不重用实例,提交之后得到的是一个新的实例(建议初学者不要轻易更改这个默认设置来在不同请求间存储变量值)。
关于ASP.NET页面生存周期中的事件和方法如下:
问:如果用.NET语言设计一个类似于Tomcat的Web服务器,你的思路是怎么样的?
Tomcat是Java中的一个Java EE容器,支持JSP和servlet。在早年的时候我曾有过模仿Tomcat的想法,所以在当时我也回答了一下我的思路。当时别人问这个问题并不是真的要我用代码去实现这么一个功能,因为大部分人都没有写Web服务器的经历,问这个问题主要是考核我在遇到以前没有遇到过的问题时的反应和思路。
问:数据库死锁是如何产生的?如何解决死锁问题?
如果说上一个问题与.NET还有一点关系的话,那么这个问题其实与.NET没有一点关系了。说实在话在被问及以前我没有遇到过数据库死锁的问题,所以也不知道如何解决。后来查阅了很多资料,对此算是有所了解,如果有人感兴趣,可以参考网址 http://www.cnblogs.com/changbluesky/archive/2010/06/10/1753021.html。
总结:在几年的被别人面试的经历中,被问过的问题不光有技术的,也有管理方面的(关于管理方面的我在博客上也谈过几个经典的问题,名字是《技术管理中常见的几个问题》),回忆其中的一些技术方面的问题总结出这些问题来。除了自己总结之外,也是给一些学会了熟练拖拽控件的程序员了解一下在ASP.NET中往深处挖可以学到的知识,当然这些只是点,掌握了这些点之后就可以尝试以点带面了,千万不要停留在表面。