问题一 C#中 property 与 attribute的区别,他们各有什么用处,这种机制的好处在哪里?
答:
关于property和attribute在很多书中都没有明显区分。我偏向于如下的理解:
特性(Attributes)是对设计时支持且又能在程序编译时起到作用的,方法/字段/类/程序集的属性声明。
属性(property)是更好地避免直接暴露你的私有成员而在类的声明的成员;
ADO架构图表 ADO.NET架构图表
问题二 ADO.NET相对于ADO有何区别和改进?答:
1. ADO以Recordset存储,而ADO.NET则以DataSet表示。Recordset看起来更像单表,如果让Recordset以多表的方式表示就必须在SQL中进行多表连接。反之,DataSet可以是多个表的集合。
2. ADO 的运作是一种在线方式,这意味着不论是浏览或更新数据都必须是实时的。ADO.NET则使用离线方式,在访问数据的时候ADO.NET会利用XML制作数据的一份幅本,ADO.NET的数据库连接也只有在这段时间需要在线。
3.由于ADO使用COM技术,这就要求所使用的数据类型必须符合COM规范,而ADO.NET基于XML格式,数据类型更为丰富并且不需要再做COM编排导致的数据类型转换,从而提高了整体性能。
问题三ASP.NET与ASP相比,主要有哪些进步?
答:
ASP.NET优点:
1. 代码和内容分离使代码更清晰
2. 提高可部署性、可伸缩性、安全性以及可靠性
3. 为不同的浏览器和设备提供更好的支持
ASP缺点:
1. ASP只能使用脚本语言属于解释性语言,主要是javascript或VBScript。而解释性语言,而解释性语言缺乏强类型和编译环境。这些将不可避免地导致性能和伸缩性问题。
2. ASP代码杂乱、功能有限,浏览器兼容以及浏览设备的兼容性差,而ASP.NET能够很好的解决。
1. SQL部分:
问:聚集索引和非聚集索引区别:
答:正文内容本身就是一种按照一定规则排列的目录称为“聚集索引”。
目录纯粹是目录,正文纯粹是正文的排序方式称为“非聚集索引”
问:索引有什么意义?简单解释 簇索引(clustered),及其优缺点
答:聚集索引通常可加快 UPDATE 和 DELETE 操作的速度,因为这两个操作需要读取大量的数据。创建或修改聚集索引可能要花很长时间,因为执行这两个操作时要在磁盘上对表的行进行重组。
但是INSERT会变慢。
可考虑将聚集索引用于:
包含数量有限的唯一值的列,如 state 列只包含 50 个唯一的州代码。
使用下列运算符返回一个范围值的查询:BETWEEN、>、>=、< 和 <=。
问:隔离级别什么意思?有几种隔离级别,分别简单解释?
答:事务准备接受不一致数据的级别称为隔离级别。隔离级别是一个事务必须与其它事务进行隔离的程度。较低的隔离级别可以增加并发,但代价是降低数据的正确性。相反,较高的隔离级别可以确保数据的正确性,但可能对并发产生负面影响。应用程序要求的隔离级别确定了 SQL Server 使用的锁定行为。
SQL-92 定义了下列四种隔离级别,SQL Server 支持所有这些隔离级别:
未提交读(事务隔离的最低级别,仅可保证不读取物理损坏的数据)。
提交读(SQL Server 默认级别)。
可重复读。
可串行读(事务隔离的最高级别,事务之间完全隔离)。
如果事务在可串行读隔离级别上运行,则可以保证任何并发重叠事务均是串行的。
问:简述对事务的理解
答:事务必须运行于可重复读或更高的隔离级别以防止丢失更新。当两个事务检索相同的行,然后基于原检索的值对行进行更新时,会发生丢失更新。如果两个事务使用一个 UPDATE 语句更新行,并且不基于以前检索的值进行更新,则在默认的提交读隔离级别不会发生丢失更新。
2. 编程语言部分(C/C++/C#)
问: 进程和线程
答: 一般进程被定义为一个程序运行中的实例。进程有两个部分组成
1. 系统内核对象(进程控制块)
2. 运行空间(包跨运行所需的代码,数据和资源,如堆和栈);
进程是不活跃的,它只提供了一个运行环境。
线程是进程中的运行分支,他在进程提供的的环境中执行代码。一个进程至少有一个线程,否则就没有存在的必要.
线程包跨一个内核对象和一个栈.线程是CPU的调度单位.
线程是进程运行的最小单位,进程参与分配资源,如句柄,内存等,线程不参与分配,呵呵,进程间通过同步,互斥,共享保持通信!
问:何时进行装箱、拆箱操作
答: 当引用类型与值类型之间转换时
问:什么是CLR
答: CLR(Common Language Runtime)普通语言运行时是整个.net framework构建的基础,是实现.Net跨平台,跨语言,代码安全等核心特性的关键
问:.Net与COM的关系是什么
答:.Net 支持COM和.Net组件之间的互操作性,实际上可通过Runtime Callable Wrapper(RCW)来实现在.Net中获取COM组件,通过COM Callable Wrapper(CCW)来实现在COM中获取.Net组件。
问:.Net中的中间语言(IL)是什么
答:.Net中的中间语言是指可以在普通语言运行时规范下,.执行时通过即时(Just In Time)编译器转化为本地代码的,与CPU独立的一族指令集合。它在.Net平台中是实现语言互操作的一个核心环节,所有.Net平台的语言都要先被编译成中间语言(IL)。
3. WEB开发部分
问:在ASP文件头部写一句什么话将使WEB SERVER强制检查任何程序中使用到的变量必须先定义
答:Option explicit
问:如果不希望某个错误影响到整个ASP页面的执行,在头部写一句什么话可以做到
答:On error resume next
问:希望ASP页面不进入缓存,即每次执行都自动刷新,写一句什么话可以做到
答: Response.Expires = -1
Response.ExpiresAbsolute = Now() - 1
Response.cachecontrol = "no-cache"
问题四 C#中的委托是什么?事件是不是一种委托?
答:
委托
委托是C#中的一种引用类型,类似于C/C++中的函数指针。与函数指针不同的是,委托是面向对象、类型安全的,而且委托可以引用静态方法和实例方法,而函数指针只能引用静态函数。委托主要用于 .NET Framework 中的事件处理程序和回调函数。
一个委托可以看作一个特殊的类,因而它的定义可以像常规类一样放在同样的位置。与其他类一样,委托必须先定义以后,再实例化。
委托派生于基类System.Delegate,不过委托的定义和常规类的定义方法不太一样。委托的定义通过关键字delegate来定义:
public delegate int myDelegate(int x,int y);
上面的代码定义了一个新委托,它可以封装任何返回为int,带有两个int类型参数的方法。任何一个方法无论是实例方法还是静态方法,只要他们的签名(参数类型在一个方法中的顺序)和定义的委托是一样的,都可以把他们封装到委托中去。
产生委托实例和产生类实例(对象)差不多,假如我们有如下的方法:
public int sub(int x,int y){
return(x+y);
}
我们就可以使用如下的代码得到一个委托实例:
myDelegate calculatin=new myDelegate(sub); // 呵呵,用方法名!!!
接下来我们就可以直接使用calculation调用sub方法了:
calculation(10,3);
当然也可以新建 委托数组,如下就建立了一个委托数组Calculation[]
接下来我们就可以直接使用calculation调用sub方法了:
calculation(10,3);
当然也可以新建 委托数组,如下就建立了一个委托数组Calculation[]
private delegate int Calculation(int a, int b);
private static Calculation[] myCalculation=new Calculation[2];
此时,可以用委托数组中的成员来封装待委托方法,实现新建委托实例.
如:
myCalculation[0]=new Calculation(MathClass.max); // 方法名
myCalculation[1]=new Calculation(MathClass.min); // 方法名
这样,也就可以用新建的委托实例数组,来直接调用方法了.
事件
在C#中,委托的最基本的一个用处就是用于事件处理。是对象发送的消息,以发信号通知操作的发生,通俗一点讲,事件就是程序中产生了一件需要处理的信号。
事件的定义用关键字event声明,不过声明事件之前必须存在一个多路广播委托(一个委托同时委托多个方法):
public delegate void Calculate(int x,int y);//返回值为void的委托自动成为多路广播委托;
public event Calculate OnCalculate;
可以看出,事件的声明仅仅是比委托实例的声明多了个关键字event,事实上事件可以看作是一个为事件处理过程定制的多路广播委托。因此,定义了事件后,我们就可以通过向事件中操作符+=添加方法实现事件的预定或者是通过操作符-=取消一个事件,这些都与委托实例的处理是相同的。
下面再单独谈谈 事件代理 的相关概念及其应用:
我们就一起来模仿一个Button类及Button值改变后引发事件并执行自定义的ButtonTextChangeEvent事件处理函数的过程,从而以事件数据得到该Button赋值过多少次。
Using System;
namespace MyServerControlTest {
public delegate void ButtonTextChangeEventHander ( object sender , EventArgs e ); //事件委托的声明。
public class Button {
public event ButtonTextChangeEventHander TxtChange;//定义一个事件委托的引用,以备外部进行事件的绑定.
private string _Text;;
public string Text {
get { return _Text;; }
set {
_Text = value;;
System.EventArgs e = new EventArgs();; //这里是事件的基类实例.
ChangeTxt(e);; //调用事件处理函数.
}
}
private void ChangeTxt(EventArgs e) { //事件处理函数.
if( TxtChange != null )
TxtChange(this,e);;//真正调用外部指派的处理函数.
}
}
}
为什么要这样定义委托声明:
delegate ButtonTextChangeEventHander (Object sender , EventArgs e )
原因也很简单,为了符合.net framework CLS的约定
Sender :引发事件的对象 ; e:事件所带的数据,而之所以用EventArgs e 是因为这里的事件是无数据的,如果自定义具有数据的事件的话,还是要从System.EventArgs基类中继承。
需要指出的是:
if( TxtChange != null )
TxtChange(this,e);;
如果不加 if( TxtChange != null )
那么当TxtChange并没有绑定事件处理函数时,它将会引发“未将对象引用到实例”的Exception。
/**//**//** 〈summary〉
/// 事件处理类
/// 〈/summary〉
public class DelegateDemo {
//定义一个实例
private Button button;
public DelegateDemo(){
InitializeComponent();
//构造函数调用时,就开始操作button进行赋值。
SetValues();
}
public void InitializeComponent(){
button = new Button();;
//对button对象的TxtChange事件引用,进行事件与处理函数的绑定。
//前面已经说过了,EventHandler是一个类,所以要用new进行创建它的实例,其主要是把button_TxtChange事件处理函数的地址传至这个委托实例。
button.TxtChange += new ButtonTextChangeEventHander(button_TxtChange);;
}
public void SetValues() {
string[] values = {"AAA","BBB","CCC","DDD","EEE"};;
for( int i = 0;; i 〈 5;; i++ ) {
//进行赋值,从而引发事件而直接调用button_TxtChange事件处理函数。
button.Text = values[i];;
}
}
private void button_TxtChange(object sender, System.EventArgs e) {
Console.WriteLine( " Button实例新值。其值为:" + ((Button)sender).Text );
}
}
public class MyMain {
public static void Main() {
DelegateDemo delegateDemo = new DelegateDemo();;
Console.Read();;
}
}
}
感觉还是讲的不是很清楚。再来看一个:
public class MyObject
{
public delegate void ClickHandler(object sender, EventArgs e);
public event ClickHandler Click;
protected void OnClick()
{
if (Click != null)
Click(this, null);
}
}
ClickHandler 代理使用事件代理的标准模式来定义事件的签名。其名称的末尾是处理程序,它带有两个参数。第一个参数是发送对象的对象,第二个参数用于传递事件的伴随信息。这种情况下没有要传递的信息,因此直接使用 EventArgs,但是如果有数据要传递,则使用从 EventArgs 派生的类(例如 MouseEventArgs)。
“Click”事件的声明执行两项操作:首先,它声明一个名为“Click”的代理成员变量,该变量从类的内部进行使用。其次,它声明一个名为“Click”的事件,该事件可按照常规访问规则从类的外部进行使用。
通常,将包括 OnClick() 等函数,以便使类型或派生类型能够触发事件。由于“Click”是代理,您将会注意到,用来触发事件的代码与代理的代码相同。
与代理类似,我们使用 += 和 -= 来挂接到事件或解除事件挂接,但与代理不同的是,仅可对事件执行这些操作。这可确保不会发生先前所讨论的两种错误。
使用事件是一种直截了当的方法。
class Test
{
static void ClickFunction(object sender, EventArgs args)
{
// process the event here.
}
public static void Main()
{
MyObject myObject = new MyObject();
myObject.Click += new MyObject.ClickHandler(ClickFunction);
}
}
我们创建一个与代理签名相匹配的静态函数或成员函数,然后用 += 向事件中添加代理的一个新实例
接下来我们就可以直接使用calculation调用sub方法了:
calculation(10,3);
当然也可以新建 委托数组,如下就建立了一个委托数组Calculation[]
问题五 描述一下C#中索引器的实现过程,是否只能根据数字进行索引?
参考答案:
索引器(Indexer)是C#引入的一个新型的类成员,它使得对象可以像数组那样被方便,直观的引用。索引器非常类似于我们前面讲到的属性,但索引器可以有参数列表,且只能作用在实例对象上,而不能在类上直接作用。下面是典型的索引器的设计,我们在这里忽略了具体的实现。
class MyClass{
public object this [int index]{
get{
// 取数据
}
set{
// 存数据
}
}
}
注意,这里的属性名是this,意思是回引类的当前实例,参数列表包含在方括号而非括号之内。索引器参数可以采用任何类型,不过int是通常采用也是最为合理的类型。同一类中还可能拥有一个以上的索引器(重载)。
问题六 C#中要使一个类支持FOREACH遍历,实现过程怎样?
若要循环访问集合,集合必须满足特定的要求。例如,在下面的 foreach 语句中:
foreach (ItemType item in myCollection)
myCollection 必须满足下列要求:
集合类型:
必须是 interface、class 或 struct。
必须包括返回类型的名为 GetEnumerator 的实例方法,例如 Enumerator。
Enumerator 类型(类或结构)必须包含:
一个名为 Current 的属性,它返回 ItemType 或者可以转换为此类型的类型。属性访问器返回集合的当前元素。
一个名为 MoveNext 的 bool 方法,它递增项计数器并在集合中存在更多项时返回 true。
有三种使用集合的方法:
1. 使用上述指导创建一个集合。此集合只能用于 C# 程序。
2. 使用上述指导创建一个一般集合,另外实现 IEnumerable 接口。此集合可用于其他语言(如 Visual Basic)。
3. 在集合类中使用一个预定义的集合。
(ms-help://MS.NETFrameworkSDKv1.1.CHS/csref/html/vclrfusingforeachwithcollections.htm#vclrfforeachcollections_example1)
问题七 ASP.NET 服务器控件的生命周期:
· 1. 初始化 - Init 事件 (OnInit 方法)
2. 加载视图状态 - LoadViewState 方法
3. 处理回发数据 - LoadPostData 方法
对实现 IPostBackDataHandler 接口的控件,即可以自动加载回发数据的控件,如 TextBox, DropDownList 等。
4. 加载 - Load 事件 (OnLoad 方法)
5. 发送回发更改通知 - RaisePostDataChangedEvent 方法
对实现 IPostBackDataHandler 接口的控件,即可以自动加载回发数据的控件。
在第 3 步中加载回发数据,如果回发前后数据发生更改,则在这一步触发相应的服务端事件。
6. 处理回发事件 - RaisePostBackEvent 方法
对实现 IPostBackEventHandler 接口的控件,即能引起回发的控件,如 Button, LinkButton, Calendar 等
7. 预呈现 - PreRender 事件 (OnPreRender 方法)
8. 保存视图状态 - SaveViewState 方法
9. 呈现 - Render 方法
10. 处置 - Dispose 方法
11. 卸载 - UnLoad 事件 (OnUnLoad 方法)
问题八 接口和抽象类有什么区别?你选择使用接口和抽象类的依据是什么?
“抽象类”是一种不能实例化而必须从中继承的类。抽象类可以完全实现,但更常见的是部分实现或者根本不实现,从而封装继承类的通用功能。
“接口”是完全抽象的成员集合,可以被看作是为操作定义合同。接口的实现完全留给开发者去做。
这里是一些建议,帮助您决定使用接口还是抽象类为组件提供多态性:
如果预计要创建组件的多个版本,则创建抽象类。抽象类提供简单易行的方法来控制组件版本。通过更新基类,所有继承类都随更改自动更新。另一方面,接口一旦创建就不能更改。如果需要接口的新版本,必须创建一个全新的接口。
如果创建的功能将在大范围的全异对象间使用,则使用接口。抽象类应主要用于关系密切的对象,而接口最适合为不相关的类提供通用功能。
如果要设计小而简练的功能块,则使用接口。如果要设计大的功能单元,则使用抽象类。
如果要在组件的所有实现间提供通用的已实现功能,则使用抽象类。抽象类允许部分实现类,而接口不包含任何成员的实现。
问题九 自定义控件和一般用户控件的异同?
用户控件模型适合创建内部,应用程序特定的控件,而自定义控件模型更适合创建通用的和可再分发的控件
问题十 面向对象的概念,主要特点
封装(wrap)、继承(inheritance)、重载(override)、多态(polymorphism)
发表于 @ 2007