由于最近找工作,不少公司给了面试题,很多定义都给忘记了,这里就把自己感觉比较重要的或经常会问到的记录一下了。
1,什么是.net,IL,CLR,CTS,GAC,GC,并且简述GC运行机制?
答:
.NET就是微软的用来实现XML,Web Services,SOA(面向服务的体系结构service-oriented architecture)和敏捷性的技术。对技术人员,想真正了解什么是.NET,必须先了解.NET技术出现的原因和它想解决的问题,必须先了解为什么他们需要XML,Web Services 和 SOA。技术人员一般将微软看成一个平台厂商。微软搭建技术平台,而技术人员在这个技术平台之上创建应用系统。从这个角度,.NET也可以如下来定义:.NET是微软的新一代技术平台,为敏捷商务构建互联互通的应用系统,这些系统是基于标准的,联通的,适应变化的,稳定的和高性能的。从技术的角度,一个.NET应用是一个运行于.NET Framework之上的应用程序。(更精确的说,一个.NET应用是一个使用.NET Framework类库来编写,并运行于公共语言运行时Common Language Runtime之上的应用程序。)如果一个应用程序跟.NET Framework无关,它就不能叫做.NET程序。比如,仅仅使用了XML并不就是.NET应用,仅仅使用SOAP SDK调用一个Web Service也不是.NET应用。.NET是基于Windows操作系统运行的操作平台,应用于互联网的分布式。
IL:中间语言
CIL:全称为通用中间语言(CIL) 是一套运作环境说明,包括一般系统、基础类库和与机器无关的中间代码。CLR则是确认操作密码符合CIL的平台。在CIL执行前,CLR必须将指令及时编译转换成原始机械码。
CLR:公共语言运行时。
CTS:通用类型系统(Common Type System)
GAC:全局程序集缓存(Global Assembly Cache,GAC)
作用是可以存放一些有很多程序都要用到的公共Assembly,例如System.Data、System.Windows.Forms等等。这样,很多程序就可以从GAC里面取得Assembly,而不需要再把所有要用到的Assembly都拷贝到应用程序的执行目录下面。举例而言,如果没有GAC,那么势必每个WinForm程序的目录下就都要从C:/WINDOWS/Microsoft.NET/Framework/v1.0.3705下面拷贝一份System.Windows.Forms.dll,这样显然不如都从GAC里面取用方便,也有利于Assembly的升级和版本控制。
2,类(class)与结构体的区别?
答:
1、结构体是值类型,类是引用类型.
2、结构体不能带有无参的构造函数,但是类可以。
3、结构体不可以实现类似于类的继承,但是可以继承接口
3,什么是委托,事件是是委托么?,什么是匿名函数,什么是Lambda表达式,什么是扩展函数?
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法
事件其实没什么不好理解的,声明一个事件不过类似于声明一个进行了封装的委托类型的变量而已。
扩展函数
public static class Extensions
{
public static int ToInt32(this string s) {
return Int32.Parse(s);
}
}
4,什么反射,反射效率怎么样?怎么样提高效率?
在开始之前,我们首先定义一个简单的对象和一个方法,以供测试之用:
1 namespace ReflectionOptimization
2 {
3 public sealed class TestObject
4 {
5 public int Add(int a, int b)
6 {
7 // 简单演示
8 return a + b;
9 }
10 }
11 }
最后我们看看如何使用委托来优化反射:
1 // 委托
2 public delegate int AddMethod(int a, int b);
3
4 // 实现
5 var obj = new TestObject();
6 var objType = obj.GetType();
7 var add = objType.GetMethod("Add");
8 var d = (AddMethod)Delegate.CreateDelegate(typeof(AddMethod), obj, add);
9
10 for (var i = 0; i < _TIMES; i++) d(a, b);
上面的代码看起来多了几行,而且还需要自定义一个委托,写起来挺麻烦的。因此我们的测试代码里面还实现了另外一种形式,其实它也是委托:
var d = (Func<TestObject, int, int, int>)Delegate.CreateDelegate(typeof(Func<TestObject, int, int, int>), add);
推荐使用委托来反射,效率高些。
5,throw与throw ex的区别?
在C#中推荐使用throw;来抛出异常;throw ex;会将到现在为止的所有信息清空,认为你catch到的异常已经被处理了,只不过处理过程中又抛出新的异常,从而找不到真正的错误源。推荐使用这种
try { } catch (Exception ex) { throw new Exception("经过进一步包装的异常", ex); }
6,验证码的实现机制,如果刷新换一张图片?
7,httpmodule,httpHander的用处与区别?
8,抽象类与接口的区别?
答:
抽象类(abstract class)可以包含功能定义和实现,接口(interface)只能包含功能定义
抽象类是从一系列相关对象中抽象出来的概念, 因此反映的是事物的内部共性;接口是为了满足外部调用而定义的一个功能约定, 因此反映的是事物的外部特性
分析对象,提炼内部共性形成抽象类,用以表示对象本质,即“是什么”
为外部提供调用或功能需要扩充时优先使用接口
以下是我在网上看到的几个形象比喻,真的非常不错,呵呵:
1.飞机会飞,鸟会飞,他们都继承了同一个接口“飞”;但是F22属于飞机抽象类,鸽子属于鸟抽象类。
2. 就像铁门木门都是门(抽象类),你想要个门我给不了(不能实例化),但我可以给你个具体的铁门或木门(多态);而且只能是门,你不能说它是窗(单继承);一个门可以有锁(接口)也可以有门铃(多实现)。 门(抽象类)定义了你是什么,接口(锁)规定了你能做什么(一个接口最好只能做一件事,你不能要求锁也能发出声音吧(接口污染)。
9,封装,继承,多态的描述使用
一、封装
1、定义
每个对象都包含它进行操作所需要的所有信息,这个特性称为封装。因此对象不必以来其他对象来完成自己的操作。这样方法和类包装在类中,通过类的实例来实现。
2、好处
- 良好的封装能够减少耦合;
- 类内部实现就可以自由地修改;
- 类具有清晰的接口;
二、继承
1、定义
继承就是从父类中获取一些公开的成员,如方法和属性。C#中只允许继承一个父类,但允许继承多个接口。如果子类继承接口,则必须实现接口中定义的所有公开成员。
公开成员是指在父类中定义为public的成员(public的作用域可在子类中生效,而private作用域则不可)
子类继承父类:
- 子类拥有父类非Private的属性和功能;
- 子类具有自己的属性和功能,即子类可以扩展父类没有的属性和功能;
- 子类还可以以自己的方式实现父类的功能(方法重写)
2、优点
继承使得所有子类公共部分都放在父类中,使得代码得到共享,这就避免了重复。此外,继承可使得修改或扩展继承而来的实现都较为容易。
三、多态
1、定义
多态是指类可以有多种形态,通过修改可以形成多个实现方法。子类从父类继承时它会获得父类的所有方法、字段、属性、事件。多态表示不同的对象可以执行相同的操作,但要通过它们自己的实现代码来执行。
若要改变父类的数据和行为,两种方式:可创建新的成员替换父级成员,或者可以重写虚拟的父级成员。
(1)若要替换父级成员,需要使用new关键字。下面是GetName方法的两种形态,一种是返回父级名称,一种是返回子级名称。
(2)重写虚拟的父级成员的两个条件:父级成员使用关键字“virtual”;子级成员使用“override”。
10,页面传值的几种方式?
答
1. 使用QueryString变量
QueryString是一种非常简单的传值方式,他可以将传送的值显示在浏览器的地址栏中。如果是传递一个或多个安全性要求不高或是结构简单的数值时,可以使用这个方法。但是对于传递数组或对象的话,就不能用这个方法了。下面是一个例子:
a.aspx的C#代码
private void Button1_Click(object sender, System.EventArgs e)
{
string s_url;
s_url = "b.aspx?name=" + Label1.Text;
Response.Redirect(s_url);
}
b.aspx中C#代码
private void Page_Load(object sender, EventArgs e)
{
Label2.Text = Request.QueryString["name"];
}
2. 使用Application 对象变量
Application对象的作用范围是整个全局,也就是说对所有用户都有效。其常用的方法用Lock和UnLock。
a.aspx的C#代码
private void Button1_Click(object sender, System.EventArgs e)
{
Application["name"] = Label1.Text;
Server.Transfer("b.aspx");
}
b.aspx中C#代码
private void Page_Load(object sender, EventArgs e)
{
string name;
Application.Lock();
name = Application["name"].ToString();
Application.UnLock();
}
3. 使用Session变量
想必这个肯定是大家使用中最常见的用法了,其操作与Application类似,作用于用户个人,所以,过量的存储会导致服务器内存资源的耗尽。
a.aspx的C#代码
private void Button1_Click(object sender, System.EventArgs e)
{
Session["name"] = Label.Text;
}
b.aspx中C#代码
private void Page_Load(object sender, EventArgs e)
{
string name;
name = Session["name"].ToString();
}
4. 使用Cookie对象变量
这个也是大家常使用的方法,与Session一样,其是什对每一个用户而言的,但是有个本质的区别,即Cookie是存放在客户端的,而session是存放在服务器端的。而且Cookie的使用要配合ASP.NET内置对象Request来使用。
a.aspx的C#代码
private void Button1_Click(object sender, System.EventArgs e)
{
HttpCookie cookie_name = new HttpCookie("name");
cookie_name.Value = Label1.Text;
Reponse.AppendCookie(cookie_name);
Server.Transfer("b.aspx");
}
b.aspx中C#代码
private void Page_Load(object sender, EventArgs e)
{
string name;
name = Request.Cookie["name"].Value.ToString();
}
5. 使用Server.Transfer方法
这个才可以说是面象对象开发所使用的方法,其使用Server.Transfer方法把流程从当前页面引导到另一个页面中,新的页面使用前一个页面的应答流,所以这个方法是完全面象对象的,简洁有效。
a.aspx的C#代码
public string Name
{
get{ return Label1.Text;}
}
private void Button1_Click(object sender, System.EventArgs e)
{
Server.Transfer("b.aspx");
}
b.aspx中C#代码
private void Page_Load(object sender, EventArgs e)
{
a newWeb; //实例a窗体
newWeb = (source)Context.Handler;
string name;
name = newWeb.Name;
}
11,http协议的工作原理?
答:无状态协议,实际上我们输入URL后,我们的浏览器给Web服务器发送了一个Request, Web服务器接到Request后进行处理,生成相应的Response,然后发送给浏览器, 浏览器解析Response中的HTML,这样我们就看到了网页,过程如下图所示
我们的Request 有可能是经过了代理服务器,最后才到达Web服务器的。
过程如下图所示
代理服务器就是网络信息的中转站,有什么功能呢?
1. 提高访问速度, 大多数的代理服务器都有缓存功能。
2. 突破限制, 也就是FQ了
3. 隐藏身份。
12,GET和POST的区别?
答:GET一般用于获取/查询资源信息,而POST一般用于更新资源信息.
1. GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditPosts.aspx?name=test1&id=123456. POST方法是把提交的数据放在HTTP包的Body中.
2. GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.
3. GET方式需要使用Request.QueryString来取得变量的值,而POST方式通过Request.Form来获取变量的值。
4. GET方式提交数据,会带来安全问题,比如一个登录页面,通过GET方式提交数据时,用户名和密码将出现在URL上,如果页面可以被缓存或者其他人可以访问这台机器,就可以从历史记录获得该用户的账号和密码.
13,viewstate,session的生命周期
答:viewstate,ViewState只能在你当前页用,可以在当前页的任何一个地方用
当aspx页面重新加载后,上一次的存放在变量中的数据就会丢失的。
用ViewState来保存
如ViewState["aaa"]="要保存的值";
下次读取的时候可以先用if(ViewState["aaa"]==null)来判断一下是否有值
ViewState["aaa"]获得是object类型的,用的时候需要转换的。
Session,一次对话,关闭浏览器,时间到期会自动销毁
session是指客户端与服务器连接到断开连接的周期!
例如:用户登陆一个论坛就会创建个session,当用户退出论坛,论坛服务器就将session回收了。
以下情况,Session结束生命周期,Servlet容器将Session所占资源释放:
1.客户端关闭浏览器
2.Session过期
3.服务器端调用了HttpSession的invalidate()方法。
13.StringBuilder 和 String 的区别?
答:String 在进行运算时(如赋值.拼接等)会产生一个新的实例,而 StringBuilder 则不会。所以在大量字符串拼接或频繁对某一字符串进行操作时最好使用 StringBuilder,不要使用 String
如果要操作一个不断增长的字符串,尽量不用String类,改用StringBuilder类。两个类的工作原理不同:String类是一种传统的修改字符串的方式,它确实可以完成把一个字符串添加到另一个字符串上的工作没错,但是在.NET框架下,这个操作实在是划不来。因为系统先是把两个字符串写入内存,接着删除原来的String对象,然后创建一个String对象,并读取内存中的数据赋给该对象。这一来二去的,耗了不少时间。而使用System.Text命名空间下面的StringBuilder类就不是这样了,它提供的Append方法,能够在已有对象的原地进行字符串的修改,简单而且直接。当然,一般情况下觉察不到这二者效率的差异,但如果你要对某个字符串进行大量的添加操作,那么StringBuilder类所耗费的时间和String类简直不是一个数量级的。
14 session与cookie区别
cookie 和session 的区别:
1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗
考虑到安全应当使用session
3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
考虑到减轻服务器性能方面,应当使用COOKIE
4、单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能3K。
5、所以个人建议:
将登陆信息等重要信息存放为SESSION
其他信息如果需要保留,可以放在COOKIE中
15:聚集索引和非聚集索引区别:
聚集索引一个表只能有一个,而非聚集索引一个表可以存在多个,这个跟没问题没差别,一般人都知道。 聚集索引存储记录是物理上连续存在,而非聚集索引是逻辑上的连续,物理存储并不连续,这个大家也都知道。
汉语字典的正文本身就是一个聚集索引。比如,我们要查“安”字,就会很自然地翻开字典的前几页,因为“安”的拼音是“an”,而按照拼音排序汉字的字典是以英文字母“a”开头并以“z”结尾的,那么“安”字就自然地排在字典的前部。如果您翻完了所有以“a”开头的部分仍然找不到这个字,那么就说明您的字典中没有这个字;同样的,如果查“张”字,那您也会将您的字典翻到最后部分,因为“张”的拼音是“zhang”。也就是说,字典的正文部分本身就是一个目录,您不需要再去查其他目录来找到您需要找的内容。正文内容本身就是一种按照一定规则排列的目录称为“聚集索引”。 如果您认识某个字,您可以快速地从自动中查到这个字。但您也可能会遇到您不认识的字,不知道它的发音,这时候,您就不能按照刚才的方法找到您要查的字,而需要去根据“偏旁部首”查到您要找的字,然后根据这个字后的页码直接翻到某页来找到您要找的字。但您结合“部首目录”和“检字表”而查到的字的排序并不是真正的正文的排序方法,比如您查“张”字,我们可以看到在查部首之后的检字表中“张”的页码是672页,检字表中“张”的上面是“驰”字,但页码却是63页,“张”的下面是“弩”字,页面是390页。很显然,这些字并不是真正的分别位于“张”字的上下方,现在您看到的连续的“驰、张、弩”三字实际上就是他们在非聚集索引中的排序,是字典正文中的字在非聚集索引中的映射。我们可以通过这种方式来找到您所需要的字,但它需要两个过程,先找到目录中的结果,然后再翻到您所需要的页码。
我们把这种目录纯粹是目录,正文纯粹是正文的排序方式称为“非聚集索引”。
通过以上例子,我们可以理解到什么是“聚集索引”和“非聚集索引”。
进一步引申一下,我们可以很容易的理解:每个表只能有一个聚集索引,因为目录只能按照一种方法进行排序。
得出查询速度的方法是:在各个select语句前加:declare @d datetime
set @d=getdate()
并在select语句后加:
select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())
1、用聚合索引比用不是聚合索引的主键速度快
2、用聚合索引比用一般的主键作order by时速度快,特别是在小数据量情况下
事实上,如果数据量很小的话,用聚集索引作为排序列要比使用非聚集索引速度快得明显的多;而数据量如果很大的话,如10万以上,则二者的速度差别不明显。
3、使用聚合索引内的时间段,搜索时间会按数据占整个数据表的百分比成比例减少,而无论聚合索引使用了多少个
4 、日期列不会因为有分秒的输入而减慢查询速度
从publish 表中取出第 n 条到第 m 条的记录:
SELECT TOP m-n+1 * FROM publish WHERE (id NOT IN (SELECT TOP n-1 id FROM publish))
id 为publish 表的关键字
只所以把“查询优化”和“分页算法”这两个联系不是很大的论题放在一起,就是因为二者都需要一个非常重要的东西――聚集索引。
在前面的讨论中我们已经提到了,聚集索引有两个最大的优势:
1、以最快的速度缩小查询范围。
2、以最快的速度进行字段排序。
第1条多用在查询优化时,而第2条多用在进行分页时的数据排序。 而聚集索引在每个表内又只能建立一个,这使得聚集索引显得更加的重要。聚集索引的挑选可以说是实现“查询优化”和“高效分页”的最关键因素。 但要既使聚集索引列既符合查询列的需要,又符合排序列的需要,这通常是一个矛盾。
聚集索引是如此的重要和珍贵,所以一定要将聚集索引建立在:
1、您最频繁使用的、用以缩小查询范围的字段上;
2、您最频繁使用的、需要排序的字段上。
16 虚方法(virtual)和抽象方法(abstract)的区别
抽象类不能被实例化,只能实例化实现了全部抽象方法的派生类
它们两个相像的一点是都用override重写
1. 虚方法必须有实现部分,抽象方法没有提供实现部分,抽象方法是一种强制派生类覆盖的方法,否则派生类将不能被实例化。
如:
//抽象方法 public abstract class Animal { public abstract void Sleep(); //不能有实现部分 public abstract void Eat(); } //虚方法
public class Animal { public virtual void Sleep(){} public virtual void Eat(){} }
2. 抽象方法只能在抽象类中声明,虚方法不是。其实如果类包含抽象方法,那么该类也是抽象的,也必须声明为抽象的。如:
public class Animal { public abstract void Sleep(); public abstract void Eat(); } 编译器会报错: Main.cs(10): 'VSTest.Animal.Sleep()' is abstract but it is contained in nonabstract class 'VSTest.Animal' Main.cs(11): 'VSTest.Animal.Eat()' is abstract but it is contained in nonabstract class 'VSTest.Animal'
3. 抽象方法必须在派生类中重写,否则派生类也为抽象类。这一点跟接口类似,虚方法不必。如:
public abstract class Animal { public abstract void Sleep(); public abstract void Eat(); } public class Cat : Animal { public override void Sleep() { Console.WriteLine( "Cat is sleeping" ); } // we need implement Animal.Eat() here } public abstract class AbsTest { public abstract void T1(); //抽象方法必须存在于抽象类中,若类不是抽象类,这报错。 public abstract void T2(); } public abstract class Test : AbsTest { public override void T1() { throw new NotImplementedException(); } //如果这里实现了T2方法,则该类不是抽象类了。 }
17.C#类和接口的区别
接口是负责功能的定义,项目中通过接口来规范类,操作类以及抽象类的概念! 而类是负责功能的具体实现! 在类中也有抽象类的定义,抽象类与接口的区别在于: 抽象类是一个不完全的类,类里面有抽象的方法,属性,也可以有具体的方法和属性,需要进一步的专业化。 但接口是一个行为的规范,里面的所有东西都是抽象的! 一个类只可以继承一个基类也就是父类,但可以实现多个接口 PS:接口除了规范一个行为之外,在具体项目中的实际作用也是十分重要的,在面向对象的设计原则以及设计模式的使用中,无不体现作为一个接口的使用好处,最直接的就是设计原则中OCP(开放封闭原则),我们使用接口,而不需要关心他的具体实现,具体实现的细节变化也无关客户端(使用接口的类)的使用,对与扩展是开放的,我们可以另写一个接口的实现来扩展当前程序,而不影响上层的使用,但对修改是封闭的,即我们不能够再去修改接口的定义,当然这个“不能够”是指在规范原则上不应该这么做!
18.抽象类(偏向于内部公共属性)和接口(偏向于行为)的区别
答:
抽象类(abstract class)可以包含功能定义和实现,
接口(interface)只能包含功能定义
抽象类是从一系列相关对象中抽象出来的概念, 因此反映的是事物的内部共性;
接口是为了满足外部调用而定义的一个功能约定, 因此反映的是事物的外部特性 分析对象,提炼内部共性形成抽象类,用以表示对象本质,即“是什么” 为外部提供调用或功能需要扩充时优先使用接口
18,Override 与New的区别
override可以覆盖基类的方法,让基类的方法以子类的内容实现,
而new不用来覆盖基类的方法,而是全新定义一个子类的方法,这个方法只属于子类,与基类的方法无关,只是名字上相同而已.
隐藏基类,就是这个类只对子类本身用,基类是不能访问的。