c#编程基础练习题与答案.docx
《c#编程基础练习题与答案.docx》由会员分享,可在线阅读,更多相关《c#编程基础练习题与答案.docx(49页珍藏版)》请在冰豆网上搜索。
c#编程基础练习题与答案
1.面向对象的思想主要包括什么
答:
个人认为一各程序语言要成为真正的面向对象的程序设计语言,它必须符合下列条件:
1抽象(abstraction)—抽象能够有效地管理一个问题的复杂性,其作法是划分出与该问题相关的一组对象.
2封装(Encapsulation)—封装是指将一个抽象的内部实现隐藏在特定的对象之内.
3多态(polymorphism)—多态会提供相同方法的多种操作方法的多种操作实作.例如,不同的对象都会拥有一个Save方法,但是每一个Save方法会执行不同的操作.
4继承(inheritance)—VisualC#2005最令人兴奋之处就是其继承特性.vc#2005则提供了真正的方法继承,因此您可以重复使用一个类的实例.
2.什么是中的用户控件
自己动手作自己的控件来取代.NET提供的控件。
这种控件就是用户控件。
后缀为.ascx
3.什么叫应用程序域什么是受管制的代码什么是强类型系统什么是装箱和拆箱什么是重载什么是多态CTS、CLS和CLR分别作何解释
应用程序域:
应用程序域(通常是AppDomain)是用于隔离应用程序的虚拟进程。
在同一个应用程序作用域中创建的所有对象(换句话说,从该应用程序的入口点开始沿着对象激活序列的任何地方)都在同一个应用程序域中创建。
多个应用程序域可以存在于一个操作系统进程中,使它们成为隔离应用程序的简便方式。
操作系统进程通过使用各不相同的内存地址空间来提供隔离。
尽管它是有效的,但也是代价昂贵的,并且不能达到大型Web服务器所需要的数量。
与其相比,公共语言运行时通过管理在应用程序域中运行的代码的内存使用来强制进行应用程序隔离。
这样就确保它不会访问应用程序域以外的内存。
需要注意的是,只有类型安全的代码才能以这种方式管理(当在应用程序域中加载不安全代码时,运行时不能保证隔离)。
理解应用程序域:
应用程序域是.NET运行库的逻辑进程表示,操作系统进程可以包含多个应用程序域。
应用程序域具有下列优点:
1、隐藏了进程具体的操作系统信息。
从而允许把.NET放在不同的操作系统下。
2、提供了隔离。
即使运行在同一个进程中的属于不同域的应用程序也不能直接共享全局数据、静态数据或其他资源。
所以,一个应用程序域失败了,也不会影响到同一个进程中的其他应用程序域。
3、对于不需要昂贵的IPC机制的进程,应用程序域允许.NET运行库优化运行在这种进程中的应用程序间的通信。
因为应用程序域是被隔离的,所有.NET对象都会被界定在创建它的应用程序域内。
如果跨应用程序域的边界传递对象引用,该被引用对象就被称为远程对象。
装箱和拆箱
在C#中的有两种类型的变量:
值类型和引用类型。
当值类型和引用类型相互转化时,会发生装箱和拆箱的过程。
这里有一点要声明:
经过拆箱或装箱的对象会多出它自己一份拷贝。
它和它的拷贝不在一个存储区域。
这也是值类型和引用类型的区别所在。
值类型总是在栈中,而引用类型总是在托管堆中。
(目前也支持了装箱和拆箱,但是我目前不知道是否和C#一样)。
为了进一步理解看下面例子:
structPoint{
publicintx;
publicinty;
}
staticvoidMain(){
Pointp;
=10;
=20;
Objecto=p;将值类型从栈中拷贝到堆中。
/************************************************************************/
*从托管堆中将对象拷贝到栈中。
/************************************************************************/
Pointp2=(Point)p;
(“:
="++“:
=“+;
=16;
=34;
(“:
="++“:
=“+;
(“:
="++“:
=“+;
}
输出结果为:
:
=10;=20;
:
=10;=20;
:
=16;=34;
可知,变量经过拆箱/装箱后,得到是自己的另一份拷贝。
装箱和取消装箱的概念是C#的类型系统的核心。
它在“值类型”和“引用类型”之间的架起了一座桥梁,使得任何“值类型”的值都可以转换为object类型的值,反过来转换也可以。
装箱和取消装箱使我们能够统一地来考察类型系统,其中任何类型的值最终都可以按对象处理
多态
一.形象理解
两条理解的原则:
(1)一个派生类对象可以被声明成一个基类,或者是一个基类指针可以指向一个派生类对象:
MainMainET结合Java和COM解决方案两者优点来解决互操作性问题。
类似于COM定义的标准二进制格式,.NET定义了一个称为通用类型系统CommonTypeSystem(CTS)的类型标准。
这个类型系统不但实现了COM的变量兼容类型,而且还定义了通过用户自定义类型的方式来进行类型扩展。
任何以.NET平台作为目标的语言必须建立它的数据类型与CTS的类型间的映射。
所有.NET语言共享这一类型系统,实现它们之间无缝的互操作。
该方案还提供了语言之间的继承性。
例如,用户能够在中派生一个由C#编写的类。
很显然,编程语言的区别不仅仅在于类型。
例如,一些语言支持多继承性,一些语言支持无符号数据类型,一些语言支持运算符重载。
用户应认识到这一点,因此.NET通过定义公共语言规范(CLS:
CommonLanguageSpecification),限制了由这些不同引发的互操作性问题。
CLS制定了一种以.NET平台为目标的语言所必须支持的最小特征,以及该语言与其他.NET语言之间实现互操作性所需要的完备特征。
认识到这点很重要,这里讨论的特征问题已不仅仅是语言间的简单语法区别。
例如,CLS并不去关心一种语言用什么关键字实现继承,只是关心该语言如何支持继承。
CLS是CTS的一个子集。
这就意味着一种语言特征可能符合CTS标准,但又超出CLS的范畴。
例如:
C#支持无符号数字类型,该特征能通过CTS的测试,但CLS却仅仅识别符号数字类型。
因此,如果用户在一个组件中使用C#的无符号类型,就可能不能与不使用无符号类型的语言(如设计的.NET组件实现互操作。
这里用的是“可能不”,而不是“不可能”,因为这一问题实际依赖于对non-CLS-compliant项的可见性。
事实上,CLS规则只适用于或部分适用于那些与其他组件存在联系的组件中的类型。
实际上,用户能够安全实现含私有组件的项目,而该组件使用了用户所选择使用的.NET语言的全部功能,且无需遵守CLS的规范。
另一方面,如果用户需要.NET语言的互操作性,那么用户的组件中的公共项必须完全符合CLS规范。
让我们来看下面的C#代码:
publicclassFoo
{
privateuintA=4;
publicuintB=5;
publiclongGetA()
{
returnA;
}
}
最后一个C是公共语言运行库CommonLanguageRuntime(CLR)。
简单地说,CLR是CTS的实现,也就是说,CLR是应用程序的执行引擎和功能齐全的类库,该类库严格按照CTS规范实现。
作为程序执行引擎,CLR负责安全地载入和运行用户程序代码,包括对不用对象的垃圾回收和安全检查。
在CLR监控之下运行的代码,称为托管代码(managedcode)。
作为类库,CLR提供上百个可用的有用类型,而这些类型可通过继承进行扩展。
对于文件I/O、创建对话框、启动线程等类型——基本上能使用WindowsAPI来完成的操作,都可由其完成。
让我们正确看待“3C”。
开发人员在构建自己的分布式应用程序时,因为用户在编程时将直接面对CLR,应将主要精力放在学习了解CLR上,而不是CTS和CLS。
而对于希望以.NET平台为目标的语言和工具开发商来说,就需要深入理解CTS和CLS。
互操作性组件是分布式应用的关键,因此理解.NET如何通过定义公共类型实现这一目标,也就显得十分重要。
4.列举一下你所了解的XML技术及其应用
5.值类型和引用类型的区别写出C#的样例代码Ref与Out的区别。
Ref与Out的区别是
相同点:
1.使参数按引用传递,注意这里的“引用”与我们通常说的“对象引用”不一样,可以形象的理解为,类似于C/C++中传指针(地址)。
2.效果是,被调用方对该参数的修改会反映到该变量中,即当调用结束返回时,调用方看到的是修改过的值。
3.方法定义和调用方法都必须显式使用ref或者out关键字
不同点:
1。
传递到ref的参数必须最先初始化,即由调用方显式初始化。
2。
传递到out的参数在传递之前不需要显式初始化,但需要调用方在方法返回之前必须对其赋值。
使用场景:
关于重载说明:
1。
ref和out关键字在运行时的处理方式不同,但在编译时的处理方式相同。
因此,如果一个方法采用ref参数,而另一个方法采用out参数,则无法重载这两个方法。
2。
但是,如果一个方法采用ref或out参数,而另一个方法不采用这两类参数,则可以进行重载。
使用ref前必须对变量赋值,out不用。
out的函数会清空变量,即使变量已经赋值也不行,退出函数时所有out引用的变量都要赋值,ref引用的可以修改,也可以不修改。
区别可以参看下面的代码:
usingSystem;
classTestApp
{
staticvoidoutTest(outintx,outinty)
{Main何理解委托
单从委托的概念上来讲,很简单,就是对方法的引用,包括静态方法和对象实例的方法,有点类似C语言中的方法指针,不过方法指针只能引用静态方法!
而且委托是类安全的!
一句话来概括:
委托就是方法的入口!
调用委托就是调用方法,可能有人会说既然调用委托就是调用方法,那为什么不直接调用方法了,干吗非得通过委托来调用!
一开始我也是这么想,包括现在也还有这个疑惑,个人觉得,如果撇开事件来说,委托除了匿名方法名称之外,没有具体实质型的好处!
意思就是说我们如果不是在事件里用委托,和直接调用方法是没有本质区别的!
至于委托的声明格式,其基本语法为:
修饰符delegate返回类型代理名称(参数列表)
比如说publicdelegatevoidMyDelegate(inti);
实例化的时候给它赋值一个方法(实例或静态方法)名就可以了MyDelegateMD=newMyDelegate(类中的方法名)
委托还可以实现多重委托,可以用Combine方法讲不同代理组在一起,也可以用Remove方法从多重代理中除去一个代理,不过在我们实际使用可以不需要这么麻烦,用+,-可以达到这个目的!
比如说:
MyDelegateMD=newMyDelegate(方法1);
MyDelegateMD2=newMyDelegate(方法2);
MyDelegateMD3=MD+MD2;
也可以这么写
MyDelegateMD3+=newMyDelegate(方法1);
MyDelegateMD3+=newMyDelegate(方法2);
执行代理MD3就是调用方法1和方法2;
多重代理个人觉得在事件委托中用处很大,因为在实际对象中,一个方法执行会触发多个方法相继执行,这个时候会需要多重代理这个概念!
使用多重代理的时候要注意方法返回类型必须是void类型的!
PS:
在代理类中有2个属性,一个是Method,表示所应用方法的名称!
另一个是Target,表示实例方法所在对象的类型,如果是静态方法,则返回NULL
事件(Event)
正如我上面说的那样,如果撇开事件,委托好像没有多大用途,但也只是假设,委托就是为事件服务的,两者是分不开的.言事件比言委托!
在C#中,事件和属性,方法一样,是类的一种成员,通过事件的使用,可以在类的对象发生某种变化,通过事件,来触发某些方法来处理事件的发生!
举个通俗的例子,在的窗体生成种,拖进来一个按钮,双击它,页面后台会自动生成按钮事件的方法名称,编程人员只要在该方法体内写上具体方法即可!
那么按钮类里面是怎么实现的了?
具体是这样的,在按钮类里面声明了一个事件委托:
publicenvetEventHandlerClick;
并写了一个触发该事件的方法:
protectedvirtualvoidOnClick(EventArgese)
{
if(Click!
=Null)
{
Click(this,e)
}
}
而什么时候调用上面这个方法,根据程序结构类型不同而异,在WEB应用程序中,是通过回传事件接口来调用上面这个方法,在按钮类里只是实现了事件委托,具体双击按钮触发的实际方法是在页面程序里编写的!
(PS:
所以这也是我认为使用事件委托的最大好处,机动行好,灵活,如果不用委托,而是直接调用方法,那么所调用的方法就固定死了,不利于实际面向对象编程中出现的未预型方法,不灵活了)
在页面程序为按钮绑定事件委托所引用的方法是开发环境自动帮我们完成的,但我们要清楚实现的必要步骤:
在页面程序里必须给按钮的事件实例化方法,在的页面代码中的privatevoidInitializeComponent()里要写上:
+=new;明事件委托;
2.触发事件的方法;
3.实例化事件委托(给委托添加引用方法)
msdn2005中是这样解释的:
委托具有以下特点:
委托类似于C++函数指针,但它是类型安全的。
委托允许将方法作为参数进行传递。
委托可用于定义回调方法。
委托可以链接在一起;例如,可以对一个事件调用多个方法。
方法不需要与委托签名精确匹配。
有关更多信息,请参见协变和逆变。
C#版引入了匿名方法的概念,此类方法允许将代码块作为参数传递,以代替单独定义的方法。
委托适用于那种在某些其他语言中需用函数指针来解决的情况(场合)。
但是,与函数指针不同,委托是面向对象和类型安全的。
委托声明定义一个类,它是从类派生的类。
委托实例封装了一个调用列表,该列表列出了一个或多个方法,每个方法称为一个可调用实体。
对于实例方法,可调用实体由一个实例和该实例的方法组成。
对于静态方法,可调用实体仅由一个方法组成。
如果用一组合适的参数来调用一个委托实例,则该委托实例所封装的每个可调用实体都会被调用,并且用的都是上述的同一组参数。
委托实例的一个有趣且有用的属性是:
它既不知道也不关心有关它所封装的方法所属的类的种种详情;对它来说最重要的是这些方法与该委托的类型兼容(第节)。
这使委托非常适合“匿名”调用。
这是一个强大的功能。
定义和使用委托分三个步骤:
声明、实例化和调用。
#中的接口和类有什么异同。
一个接口定义一个协定。
实现接口的类或结构必须遵守其协定。
接口可以包含方法、属性、索引器和事件作为成员。
接口是负责功能的定义,项目中通过接口来规范类,操作类以及抽象类的概念!
而类是负责功能的具体实现!
在类中也有抽象类的定义,抽象类与接口的区别在于:
抽象类是一个不完全的类,类里面有抽象的方法,属性,也可以有具体的方法和属性,需要进一步的专业化。
但接口是一个行为的规范,里面的所有东西都是抽象的!
一个类只可以继承一个基类也就是父类,但可以实现多个接口
PS:
接口除了规范一个行为之外,在具体项目中的实际作用也是十分重要的,在面向对象的设计原则以及设计模式的使用中,无不体现作为一个接口的使用好处,最直接的就是设计原则中OCP(开放封闭原则),我们使用接口,而不需要关心他的具体实现,具体实现的细节变化也无关客户端(使用接口的类)的使用,对与扩展是开放的,我们可以另写一个接口的实现来扩展当前程序,而不影响上层的使用,但对修改是封闭的,即我们不能够再去修改接口的定义,当然这个“不能够”是指在规范原则上不应该这么做!
9.。
net中读写数据库需要用到哪些类他们的作用
连接和TCP连接的异同。
的身份验证方式有哪些分别是什么原理
12.进程和线程分别怎么理解
简单的说,你每启动一个程序,就启动了一个进程。
在Windows下,进程是最小运行单位。
在Windows95/NT下,每个进程还可以启动几个线程,比如每下载一个文件可以单独开一个线程。
在Windows95/NT下,线程是最小单位。
WINDOWS的多任务特性使得线程之间独立运行,但是它们彼此共享虚拟空间,也就是共用变量,线程有可能会同时操作一片内存。
线程与进程的区别多线程共存于应用程序中是现代操作系统中的基本特征和重要标志。
用过UNIX操作系统的读者知道进程,在UNIX操作系统中,每个应用程序的执行都在操作系统内核中登记一个进程标志,操作系统根据分配的标志对应用程序的执行进行调度和系统资源分配,但进程和线程有什么区别呢进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。
进程和线程的区别在于:
线程的划分尺度小于进程,使得多线程程序的并发性搞。
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程在执行过程中与进程还是有区别的。
每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口
13.什么是code-Behind技术。
14.活动目录的作用。
15.中读写XML的类都归属于哪些命名空间
16.解释一下UDDI、WSDL的意义及其作用。
17.什么是SOAP,有哪些应用。
答:
SOAP(SimpleObjectAccessProtocol)简单对象访问协议是在分散或分布式的环境中交换信息并执行远程过程调用的协议,是一个基于XML的协议。
使用SOAP,不用考虑任何特定的传输协议(最常用的还是HTTP协议),可以允许任何类型的对象或代码,在任何平台上,以任何一直语言相互通信。
这种相互通信采用的是XML格式的消息,具体请看如何部署一个页面。
19.如何理解中的垃圾回收机制。
20.常用的调用webservice方法有哪些
与abstraction区别
22.结构与类有何差异哪些时候比较适合使用结构和类
它们的相同之处:
1,两者都是Container类型,这表示它们可以包含其他数据类型作为成员.
2,两者都拥有成员,这些成员包括:
构造函数,方法,属性,字段,常量,枚举类型,事件,以及事件处理函数.
3,两者的成员都有其各自的存取范围.例如,您可以将某一个成员声明为Public,而将另外一人成员声明为Private
4,两者都可以实现接口.
5,两者都可以公开一个默认属性,然而前提是这个属性至少要取得一个自变量.
6,两者都可以声明和触发事件,而且两者都可以声明委托(Delegate).
7,结构与类都可以完全是空的.
它们的不同之处如下:
1,结构是实值类型(ValueTypes),而类是引用类型(ReferenceTypes).
2,结构使用载存储(StackAllocation),而类使用堆存储(HeapAllocation).
3,所有结构成员默认都是Public,而类的变量与常量数则默认为(Private,不过其他类成员默认都是Public.
4,结构成员国不能被声明为Protected,但是类成员可以这样做.
5,结构变量声明不能指定初始值,使用new关键字词或对数组进行初始化,但类变量声明则可以这样做.
6,结构不能声明默认的构造函数,也就是不拥有参数的非共享构造函数,但是类则无此限制.
7,二者都可以拥有共享构造函数,结构的共享构造函数不能带有参数,但类的共享构造函数则可以带或者不带参数.
8,结构不允许声明析构函数(Destructor),类则无此限制.
9,结构的实例(Instance)声明,不允许对包含的变量进行初始化设定,类则可以在声明类的实例时,同时进行变量初始化.
10,结构是隐式继承自ValueType类而且不能继承任何其它的类型,类则可以继承来自ValueType以外的任何类.
11,结构是无法被继承的,类则可以被继承.
12,结构永远不会终止,因此CommonLanguageRuntime(CLR)不会在任何结构上调用Finalize方法.类则是由内存回收进程加以终止,当内存回收进程检测到没有任何作用的类时,它就会调用类的Finalize方法.
13,结构不需要构造函数,类则需要构造函数.
14,结构只能在一种情况下使用非共享构造函数,那就是非共享构造函数会接收参数:
但是类则无此限制,它可以使用带参数或不带参数的非共享构造函数.
15,每一个结构都具有无参数的隐含公共构造函数.此构造函数会将结构的所有成员初始化为基默认值.您不能重新定义这个行为.
除了上述的相似处与相异点之外,我们还可以在”实例与变量”层面上来探讨结构与类.由于结构是数值类型的,因此每个结构变量会永久地绑定到结构实例上.然而类是引用类型的,而且对象变量可引用不同的类实例.在此方面的区别,会对于使用结构与类造成下列影响:
1结构变量会隐式地使用结构的无参数构造函数来初始化成员,这就意味着,语句StructlS
就等于StructlS=newStructl();
2当您好将一个结构变量赋值给另一个,或是将结构实例传递到程序变量时,所有变量成员的值会复制到新的结构中.当您将一个对象变量赋值给另一个,或是将对象变量传递到程序时,则只会复制指针.
3,您可以将Null值赋值给结构变量,但是该实例会一直与该变量保持关联.虽然变量成员会因此赋值而重新初始化,但是您还是可以调用变量的方法并访问其数据成员.相反地,如果您将对象变量设定为Null,您就会中断它与任何类实例的关联,而且除非您再将另外一个实例赋值给它,否则无法通过变量访问任何成员.
4,您可以在不同时间将不同的类的实例赋值给同一个对象变量,而且在同一时间可以有好几个对象变量引用相同的类实例,如果您对类成员值做了改变,则其它指向相同实例的对象变量也会发生改变.然而,结构成员则会封装在它们自己的实例中,变更结构成员值并不会对其它任何结构变量的成员造成影响,甚至也不会影响相同Struct声明的其它实例.
5,两个结构必须以成员对成员的比较方式来执行相等比较.两个对象变量可以使用Equals方法来加以比较.Equals会判断两个变量是否指向相同的实例.
在下列状况中,比较适合使用结构
1,您拥有少量数据而且希望使用会传递的方式来为变量赋值时.
2您会在每一个实例上执行大量的操作,而且若使用堆来管理会造成性能下降.
3,您不需要进行继承,而且不需要实例有特殊性.
4,您不会采用Boxing与Unboxing结构.
5,您会在Managed与UnManaged程序代码之间传递Blittable数据.
在下列情况中,比较适合使用类:
1,您需要使用继承与多态.
2,您需要在创建阶段初始化一个或多个成员.
3,您需要提供一个非参数型的构造函数.
4,您需要没有任何限制的事件处理支持.
23.谈谈你对二维树的理解
24.如何把一个array复制到arrayList里
foreach(objectoinarray)(o);
可以连接什么数据源[dataset,datatable,dataview]
dataset,datatable,dataview,IList
26.概述反射和序列化
反射:
程序集包含模块,而模块包含类型,类型又包含成员。
反射则提供了封装程序集、