c# 曾经面试题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c# 曾经面试题相关的知识,希望对你有一定的参考价值。
1.c#中public\\protect\\private\\internal修饰符的区别
public 关键字是类型和类型成员的访问修饰符。公共访问是允许的最高访问级别,对访问公共成员没有限制。
protected 关键字是一个成员访问修饰符。受保护成员在它的类中可访问并且可由派生类访问。
private 关键字是一个成员访问修饰符。私有访问是允许的最低访问级别。私有成员只有在声明它们的类和结构体中才是可访问的。
internal 关键字是类型和类型成员的访问修饰符。只有在同一程序集的文件中,内部类型或成员才是可访问的。
public 意味着在其后声明的所有成员对所有的人都可以取。
private 关键字意味着除了该类型的创建者和类的内部成员函数之外,任何人都不能存取这些成员。
protect 它与private基本相似,只有一点不同:继承的结构可以访问protected成员,但不能访问private成员。
2.ASP.NEt的几种传值方式,及特点http://www.cnblogs.com/zhangkai2237/archive/2012/05/06/2486462.html
常用的较简单有QueryString,Session,Cookies,Application,Server.Transfer。
一、QueryString
QueryString是一种非常简单的传值方式,他可以将传送的值显示在浏览器的地址栏中。如果是传递一个或多个安全性要求不高或是结构简单的数值时,可以使用这个方法。但是对于传递数组或对象的话,就不能用这个方法了。
这种方法的优点:1.使用简单,对于安全性要求不高时传递数字或是文本值非常有效。
这种方法的缺点:1.缺乏安全性,由于它的值暴露在浏览器的URL地址中的。
2.不能传递对象。
使用方法:1.在源页面的代码中用需要传递的名称和值构造URL地址。
2.在源页面的代码用Response.Redirect(URL);重定向到上面的URL地址中。
3.在目的页面的代码使用Request.QueryString["name"];取出URL地址中传递的值。
二、Session:其操作与Application类似,作用于用户个人,所以,过量的存储会导致服务器内存资源的耗尽。
优点:1.使用简单,不仅能传递简单数据类型,还能传递对象。
2.数据量大小是不限制的。
缺点:1.在Session变量存储大量的数据会消耗较多的服务器资源。
2.容易丢失。
使用方法:1.在源页面的代码中创建你需要传递的名称和值构造Session变量:Session["Name"]="Value(Or Object)";
2.在目的页面的代码使用Session变量取出传递的值。Result = Session["Nmae"]
注意:session不用时可以销毁它,销毁的方法是:清除一个:Session.Remove("session名");
清除所有:Session.Clear();
三、Cookie:用于在用户浏览器上存储小块的信息,保存用户的相关信息,比如用户访问某网站时用户的ID,用户的偏好等,用户下次访问就可以通过检索获得以前的信息。所以Cookie也可以在页面间传递值。Cookie通过HTTP头在浏览器和服务器之间来回传递的。Cookie只能包含字符串的值,如果想在Cookie存储整数值,那么需要先转换为字符串的形式。
优点:1.使用简单,是保持用户状态的一种非常常用的方法。比如在购物网站中用户跨多个页面表单时可以用它来保持用户状态。
缺点:1.常常被人认为用来收集用户隐私而遭到批评。
2.安全性不高,容易伪造。
使用方法:1.在源页面的代码中创建你需要传递的名称和值构造Cookie对象:
四、Application:对象的作用范围是整个全局,也就是说对所有用户都有效。它在整个应用程序生命周期中都是有效的,类似于使用全局变量一样,所以可以在不同页面中对它进行存取。它和Session变量的区别在于,前者是所有的用户共用的全局变量,后者是各个用户独有的全局变量。
优点:1.使用简单,消耗较少的服务器资源。
2.不仅能传递简单数据,还能传递对象。
3.数据量大小是不限制的。
缺点:1.作为全局变量容易被误操作。所以单个用户使用的变量一般不能用application。
使用方法:1.在源页面的代码中创建你需要传递的名称和值构造Application变量:Application["Nmae"]="Value(Or Object)";
2.在目的页面的代码使用Application变量取出传递的值。Result = Application["Nmae"]
注意:常用lock和unlock方法用来锁定和解锁,为了防止并发修改。
五、Server.Transfer:其使用Server.Transfer方法把流程从当前页面引导到另一个页面中,新的页面使用前一个页面的应答流,所以这个方法是完全面象对象的,简洁有效。
Server.Transfer是从当前的ASPX页面转到新的ASPX页面,服务器端执行新页并输出,在新页面中通过Context.Handler来获得前一个页面传递的各种数据类型的值、表单数据、QueryString.由于重定向完全在服务器端完成,所以客户端浏览器中的URL地址是不会改变的。调用Server.Transfer时,当前的ASPX页面终止执行,执行流程转入另一个ASPX页面,但新的ASPX页面仍使用前一ASPX页面创建的应答流。
ps:比较Server.Transfer和Response.Redirect的区别。
(1)Server.Transfer在服务器端完成,所以客户端浏览器中的URL地址是不会改变的;Response.Redirect是客户端完成,向服务器端提出新的页面处理请求,所以客户端浏览器中的URL地址是会改变的。
(2)Server.Transfer在服务器端完成,不需要客户端提出请求,减少了客户端对服务器端提出请求。[2]
(3)Server.Transfer只能够转跳到本地虚拟目录指定的页面,也就是工程项目中的页面,而Response.Redirect则十分灵活,可以跳转到任何URL地址。
(4)Server.Transfer可以将前一个页面的各种类型的值传到新的页面;Response.Redirect则只能借助URL中带参数或是结合上面四种办法把各种类型的值传到新的页面。
优点:1.直接在服务器端重定向,使用简单方便,减少了客户端对服务器端提出请求。
2.可以传递各种数据类型的值和控件的值。
缺点:1.客户端浏览器中的URL地址是不改变,会导致在新的页面可能出现一些意想不到的问题。比如如果源页面和目的页面不在同一个虚拟目录或其子目录下,那么使用相对路径的图片、超链接都会导致错误的指向。
使用方法:1.在源页面的代码中,使用Page类的Server.Transfer跳到另一个页面传递页面数据:Server.Transfer("b.aspx","false")。
2.在目的页面中,使用Context.Handler来接收数据:FormerPage formerPage = (FormerPage)Context.Handler; 然后用formerPage的属性和方法来获取前一个页面的值,或者直接用Context.Items["myParameter "]
3.debug build和release build的区别
Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。
Debug和Release的区别,还在于一组编译选项(这里省略...),实际上,Debug和Release并没有本质的界限,他们只是一组编译选项的集合,编译器只是按照预定的选项行动。事实上,我们甚至可以修改这些选项,从而得到优化过的调试版本或是带跟踪语句的发布版本。
只有Debug版的程序才能设置断点、单步执行、使用TRACE/ASSERT等调试输出语句。Release不包含任何调试信息,所以体积小、运行速度快。
4.a.equals(b)与a==b是否相同
对于值类型相同,对于引用类型不同,equals是内容,==是地址
5.get和post的区别
get一般为链接方式,post一般为按钮方式。
6.什么叫做SQL注入,如何防止?请举例说明。
答:利用sql关键字对网站进行攻击。过滤关键字‘等
7.string和stringBuilder的区别
String是不可改变的,没事使用String类中的方法时,都要在内存中创建一个新的字符串对象,就是需要为该对象分配新的空间。需要对字符串执行重复修改的情况下,String对象相关的系统开销会非常昂贵。在需要对字符串执行重复修改的情况下,可以使用StringBuild类
算法题:
-
取出int数组中最大的10个数
2. string[]的字典排序
3. 现有一int类型数值,想用“,”以N位分割表示输出(例:int val=18943232,想以18,943,232格式输出,其中相隔3位数相隔是变量N),请写出关键算法
sql知识
1.索引的作用,主键是索引么?聚集索引和非聚集索引的区别
2.维护数据库的完整性和一致性,你喜欢用触发器还是自写业务逻辑?为什么?
3.对于数据库的查询优化,应该从哪几方面考虑?
-
一组指定的字符串,统计出该串各字符出现的次数,并打印出出现次数最多的那个字符
string str = "jintiantianqihaoqinglang";
Dictionary<char,int> dic=new Dictionary<char,int>();
foreach (char ch in str)
{
if (dic.Keys.Contains(ch))
{
dic[ch]++;
}
else
{
dic.Add(ch, 1);
}
2.C#中关键字new有几种用法,using有几种用法
using的用法:1.using+ 命名空间
2.using别名。using + 别名 = 包括详细命名空间信息的具体的类型。
using
aClass = NameSpace1.MyClass;
using
bClass = NameSpace2.MyClass;
aClass my1 = new aClass();
bClass my2 = new bClass();
3.using语句,定义一个范围,在范围结束时处理对象。
场景:
当在某个代码段中使用了类的实例,而希望无论因为什么原因,只要离开了这个代码
段就自动调用这个类实例的Dispose。 要达到这样的目的,用try...catch来捕捉异
常也是可以的,但用using也很方便。
new的用法:
1)new 运算符:用于创建对象和调用构造函数。这种大家都比较熟悉,没什么好说的了。
2)new 修饰符:在用作修饰符时,new 关键字可以显式隐藏从基类继承的成员。
BaseA中有变量X,方法Invoke()和 TrueValue(), DerivedB用new显示从继承基类成员
public class DerivedB : BaseA
{
new public int x = 2;
new public void Invoke()
{
Console.WriteLine(x.ToString());
}
new public int TrueValue
{
get { return x; }
set { x = value; }
}
}
3)new 约束:用于在泛型声明中约束可能用作类型参数的参数的类型。
AOP: Aspect Oriented Programming 面向切面编程。
面向切面编程(也叫面向方面):Aspect Oriented Programming(AOP),是目前软件开发中的一个热点。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP是OOP的延续,是(Aspect Oriented Programming)的缩写,意思是面向切面(方面)编程。
主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。
主要的意图是:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改 变这些行为的时候不影响业务逻辑的代码。
可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可以说也是这种目标的一种实现。
假设把应用程序想成一个立体结构的话,OOP的利刃是纵向切入系统,把系统划分为很多个模块(如:用户模块,文章模块等等),而AOP的利刃是横向切入系统,提取各个模块可能都要重复操作的部分(如:权限检查,日志记录等等)。由此可见,AOP是OOP的一个有效补充。
注意:AOP不是一种技术,实际上是编程思想。凡是符合AOP思想的技术,都可以看成是AOP的实现。
4.如果网站打开缓慢,如何定位原因?如何优化?
5.MSSQL的锁机制
共享锁
共享 (S) 锁允许并发事务读取 (SELECT) 一个资源。资源上存在共享 (S) 锁时,任何其它事务都不能修改数据。一旦已经读取数据,便立即释放资源上的共享 (S) 锁,除非将事务隔离级别设置为可重复读或更高级别,或者在事务生存周期内用锁定提示保留共享 (S) 锁。
更新锁
更新 (U) 锁可以防止通常形式的死锁。一般更新模式由一个事务组成,此事务读取记录,获取资源(页或行)的共享 (S) 锁,然后修改行,此操作要求锁转换为排它 (X) 锁。如果两个事务获得了资源上的共享模式锁,然后试图同时更新数据,则一个事务尝试将锁转换为排它 (X) 锁。共享模式到排它锁的转换必须等待一段时间,因为一个事务的排它锁与其它事务的共享模式锁不兼容;发生锁等待。第二个事务试图获取排它 (X) 锁以进行更新。由于两个事务都要转换为排它 (X) 锁,并且每个事务都等待另一个事务释放共享模式锁,因此发生死锁。
若要避免这种潜在的死锁问题,请使用更新 (U) 锁。一次只有一个事务可以获得资源的更新 (U) 锁。如果事务修改资源,则更新 (U) 锁转换为排它 (X) 锁。否则,锁转换为共享锁。
排它锁
排它 (X) 锁可以防止并发事务对资源进行访问。其它事务不能读取或修改排它 (X) 锁锁定的数据。
意向锁
意向锁表示 SQL Server 需要在层次结构中的某些底层资源上获取共享 (S) 锁或排它 (X) 锁。例如,放置在表级的共享意向锁表示事务打算在表中的页或行上放置共享 (S) 锁。在表级设置意向锁可防止另一个事务随后在包含那一页的表上获取排它 (X) 锁。意向锁可以提高性能,因为 SQL Server 仅在表级检查意向锁来确定事务是否可以安全地获取该表上的锁。而无须检查表中的每行或每页上的锁以确定事务是否可以锁定整个表。
意向锁包括意向共享 (IS)、意向排它 (IX) 以及与意向排它共享 (SIX)。
http://www.jb51.net/article/40631.htm、
-
类中的函数不仅能存取类中的私有数据,而且可以存取类的静态成员数据(√)
-
==与Equals
对于值类型,如果对象的值相等,则相等运算符 (==) 返回 true,否则返回 false。对于string 以外的引用类型,如果两个对象引用同一个对象,则 == 返回 true。对于 string 类型,== 比较字符串的值。
==操作比较的是两个变量的值是否相等。
equals()方法比较的是两个对象的内容是否一致.equals也就是比较引用类型是否是对同一个对象的引用。
class Program
{
static void Main(string[] args)
{
string a = new string(new char[] { ‘H‘, ‘E‘, ‘L‘, ‘L‘, ‘O‘ });
string b = new string(new char[] { ‘H‘, ‘E‘, ‘L‘, ‘L‘, ‘O‘ });
Console.WriteLine(a == b); //True
Console.WriteLine(a.Equals(b)); //True
object g = a;
object h = b;
Console.WriteLine(g == h); //False
Console.WriteLine(g.Equals(h)); //True
Person p1 = new Person("jia");
Person p2 = new Person("jia");
Console.WriteLine(p1 == p2); //False
Console.WriteLine(p1.Equals(p2)); //False
Person p3 = new Person("jia");
Person p4 = p3;
Console.WriteLine(p3 == p4); //True
Console.WriteLine(p3.Equals(p4)); //True
Console.ReadKey();
}
}
class Person
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
public Person(string name)
{
this.name = name;
}
}
总结:
a.值类型和引用类型
值类型存储在栈中,而引用类型的变量在栈仅仅是存储引用类型变量的地址,而其本身则存储在堆中。
==比较的是两个变量的值是否相等,对于引用类型变量表示的是两个变量在堆中存储的地址是否相同,及栈中内容是否相同
equals操作表示的两个变量是否是对同一对象的引用,即堆中的内容是否相同
b.对于object g 和object h 时内存中两个不同的对象所以在栈中的内容是不同的,故不相等。而g.equals(h)用的是string 的equals()方法故相等。如果将字符串a和b做这样的修改:string a=”aa“;string b="aa" 则g和h的两个比较都是相等的。这事因为系统并没有给字符串b分配内存,只是将”aa“指向了b。所以a和b执行的是同一个字符串。
c.类p1和p2
也是内存中两个不同的对象,所以在内存中的地址肯定不相同,故P1==P2会返回false,又因为p1和p2又是不同对象的引用,所以p1.equals(p2)将返回false/
d.类P3和P4
p4=p3,P3将对对象的引用赋给了P4,P3和P4是对同一个对象的引用,所以两个比较都返回了true
e.重新类Person中的equals方法后,p1.equals(p2)将返回True.
class Person
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
public Person(string name)
{
this.name = name;
}
public override bool Equals(object obj)
{
if (!(obj is Person))
return false;
Person per = (Person)obj;
return this.Name == per.Name;
}
}
3. 数据库的主键最多只有一个,但可以有很多的唯一键
abstract, extern, or partial 在类中不进行实现
4.接口可以继承接口,抽象类可以实现接口,但抽象类不能继承实体类
抽象类和接口的区别:http://kb.cnblogs.com/page/41836/
抽象类:特殊的类,不能被实例化,除此之外,具有类的特性。重要的是抽象类可以包括抽象方法,这是普通类所不能的。抽象方法只能声明于抽象类中,且不包括任何实现(abstract, extern, or partial 在类中不进行实现),派生类必须覆盖它们。另外抽象类可以派生自一个抽象类,可以覆盖基类的抽象方法也可以不覆盖,如果不覆盖,则其派生类必须覆盖它们。
接口:接口是引用类型,和抽象类的相似之处
-
不能实例化;2.包含未实现的方法声明,3.派生类必须实现未实现的方法,抽象类是抽象方法,接口则是所有成员(不仅是方法包括其他成员)
接口还有如下特性:接口除了包含方法之外,还可以包括属性、索引器、事件,而且这些成员都被定义为共有的。除此之外,不能包含任何其他成员,例如:常量,域,构造函数,析构函数,静态成员。
抽象类与接口的区别:
-
类是对对象的抽象,可以把抽象类理解为把类当对象,抽象成的类叫做抽象类。而接口只是 一个行为的规范或规定。抽象类更多的是定义在一系列紧密相关的类间,而接口大多是关系疏松但都实现某一功能的类中
-
接口基本不具备继承的任何具体特点,它仅仅承诺了能够调用的方法
-
一个类一次可以实现若干个接口,但是只能扩展一个父类
-
接口可以用于支持回调,而继承并不具备 这个特点
-
抽象类不能被密封
-
抽象类实现的具体方法默认为虚的,但实现接口的类中的接口方法默认为非虚的 ,自己可以声明为虚的
-
接口与非抽象类类似,抽象类也必须为在该类的基类列表中列出的接口的所有成员提供它自己的实现。但是,允许抽象类将接口方法映射到抽象方法上
-
抽象类实现了OOP的一个原则,把可变的与不可变的分离。接口和抽象类就是定义为不可变的,而把可变的放到子类去实现
-
好的接口定义应该具有专一功能性,而不是多功能的,否则造成接口污染。如果一个类只实现了这个接口中的一个功能,而不得不去实现接口中的其他方法,这就叫接口污染
-
如果抽象类实现接口,则可以把接口中方法映射到抽象类中作为抽象方法而不必实现,而在抽象类的子类中实现接口中方法。
抽象类和接口的使用:
1. 如果预计要创建组件的多个版本,则创建抽象类。抽象类提供简单的方法来控制组件版本
2. 如果创建的功能要在大范围的全异对象中使用,则使用接口,如果要设计小而简练的功能块,则使用接口
3. 如果要设计大的功能单元,则使用抽象类,如果要在组件的所有实现间提供通用的已实现功能,则使用抽象类
4. 抽象类主要用于关系密切的对象,而接口适合为不相关的类提供通用功能
以下是我在网上看到的几个形象比喻。
1.飞机会飞,鸟会飞,他们都继承了同一个接口“飞”;但是F22属于飞机抽象类,鸽子属于鸟抽象类;
2. 就像铁门木门都是门(抽象类),你想要个门我给不了(不能实例化),但我可以给你个具体的铁门或木门(多态);而且只能是门,你不能说它是窗(单继承),一个门可以有锁(接口)也可以有门铃(多实现)。门(抽象类)定义了你是什么,接口(锁)规定了你能做什么(一个接口最好只能做一件事,你不能要求锁也能发出声音吧(接口污染))。
静态类:
静态类不能被实例化,我们直接使用它的属性与方法,静态类最大的特点就是共享
1. 静态类中的成员必须是静态的
2. 静态类可以有静态静态构造函数,静态构造函数不可继承
3. 静态构造函数可以用于静态类,也可以 用于非静态类
4. 静态构造函数无访问修饰符、无参数,只有一个static标志
5. 静态构造 函数不可被直接调用,当创造类实例或引用任何静态成员之前,静态构造函数被自动执行,并且只执行一次
结构
-
没有默认的构造函数,但是可以添加构造函数
-
没有析构函数
-
没有 abstract 和 sealed(因为不能继承)
-
不能有 protected 修饰符
-
可以不使用 new 初始化
-
在结构中初始化实例字段是错误的
类
-
有默认的构造函数
-
有析构函数
-
可以使用 abstract 和 sealed
-
有 protected 修饰符
-
必须使用 new 初始化
相同之处:
-
结构和类对于程序来讲都通过指针操作,同样是面向对象的形式。
不同之处:
-
结构体对象总是在线程堆栈上操作,而不是托管堆上。
-
不能继承一个结构体(所以在调用结构体的方法时不需要查找 vtable: 虚函数继承表)
-
我们不能声明构造函数为空的结构体(不晓得为啥非得要这么设计)
-
结构体的构造函数内必须初始化所有变量(不晓得为啥非得要这么设计)
-
结构体的字段不能有默认值(默认都是二进制意义上的零值),但是可以在构造函数内改变“默认值”
虚函数:
ref 和 out 的区别:
首先:两者都是按地址传递的,使用后都将改变原来参数的数值。
其次:ref可以把参数的数值传递进函数,但是out是要把参数清空,就是说你无法把一个数值从out传递进去的,out进去后,参数的数值为空,所以你必须初始化一次。这个就是两个的区别,或者说就像有的网友说的,ref是有进有出,out是只出不进。
尽管 ref 和 out 在运行时的处理方式不同,但在编译时的处理方式相同。因此,如果一个方法采用 ref 参数,而另一个方法采用 out 参数,则无法重载这两个方法。
如果一个方法采用 ref 或 out 参数,而另一个方法不采用这两个参数,则可以进行重载,
8.linq
9.虚方法和抽象方法
以上是关于c# 曾经面试题的主要内容,如果未能解决你的问题,请参考以下文章
如何为 XSLT 代码片段配置 CruiseControl 的 C# 版本?