• 164.00 KB
  • 2022-04-22 11:19:43 发布

C#习题参考答案 《c#面向对象程序设计》 郑宇军.doc

  • 22页
  • 当前文档由用户上传发布,收益归属用户
  1. 1、本文档共5页,可阅读全部内容。
  2. 2、本文档内容版权归属内容提供方,所产生的收益全部归内容提供方所有。如果您对本文有版权争议,可选择认领,认领后既往收益都归您。
  3. 3、本文档由用户上传,本站不保证质量和数量令人满意,可能有诸多瑕疵,付费之前,请仔细先通过免费阅读内容等途径辨别内容交易风险。如存在严重挂羊头卖狗肉之情形,可联系本站下载客服投诉处理。
  4. 文档侵权举报电话:19940600175。
'习题参考答案Chapter11_1对象客观世界中的事物都是对象,包括有形的物理对象,可感知的逻辑实体,以及概念化的抽象实体。它有自己的属性,能够执行特定的操作。类具有相同属性和操作的一组对象的集合;它描述的不是单个对象,而是“一类”对象的共同特征。其重要性在于它是面向对象技术中最重要的结构,它支持信息隐藏和封装,进而支持对抽象数据类型(ADT)的实现。1_2略1_3参考图如下图11_4UML与面向对象UML是一种定义良好、易于表达、功能强大且普遍适用的建模语言。它溶入了软件工程领域的新思想、新方法和新技术。它的作用域不限于支持面向对象的分析与设计,还支持从需求分析开始的软件开发的全过程。标准建模语言UML适用于以面向对象技术来描述任何类型的系统,而且适用于系统开发的不同阶段,从需求规格描述直至系统完成后的测试和维护。 Chapter22_1程序的功能一般通过方法代码来实现。每个方法都是从其第一行代码开始执行,直至最后一行代码结束,期间可以通过代码来调用其他的方法,从而完成各式各样的操作。C#程序的起点是由Main方法定义的,程序总是从Main方法的第一行代码开始执行,在Main方法结束时停止运行。2_2略(注:不同版本的VisualStudio的菜单项有所区别)2_3略(注:不同版本的VisualStudio引用的程序集有所区别)2_4 C#源代码会被编译为一种通用的中间语言(IL)代码,该语言类似于低级语言,但其代码与具体的硬件平台无关;之后CLR再针对特定的平台将IL程序翻译为机器指令,加载所需要的资源并管理执行。2_5 //动态链接库程序usingSystem;namespacep2_5{classAdder{publicstaticintAdd(inta,intb){returna+b;}}}//控制台应用程序usingSystem;usingp2_5;namespaceP2_6{classProgram{staticvoidMain(){Console.WriteLine("请输入两个数:");inta=int.Parse(Console.ReadLine());intb=int.Parse(Console.ReadLine());Console.WriteLine("{0}+{1}={2}",a,b,Adder.Add(a+b));}}}Chapter33_1略3_2第一:值类型的变量直接包含自身的所有数据,每创建一个变量,就在内存中开辟一块区域;只有通过变量才能修改它所包含的数据。而引用类型的变量只存储对目标数据的引用,每创建一个变量,就增加一个指向目标数据的指针;有可能出现多个引用类型的变量指向同一份数据的情况,这时修改一个变量就会影响到其它所有的变量。第二:作为方法参数时,值类型变量传递的是数值,引用类型变量传递的是地址,因此如果方法的执行代码修改了变量,对值类型的变量不会有影响,但会改变引用类型的变量。 第三:装箱是将一个值类型转换为一个对象类型(object),而拆箱则是将一个对象类型显式转换为一个值类型。3_3略3_4对整数为真,对实数不一定,因为实数受到计算机精度的影响。3-5四次执行的结果分别是:3,6,-6,-33-6当两个操作数均为布尔类型时,与运算“&”和逻辑与运算“&&”的求值效果相同,或运算“|”和逻辑或运算“||”的求值效果相同。但异或运算“^”不存在对应的条件逻辑运算。3-7不是。if-else可进行任意分支,而“?:”操作符要求第二和第三个操作数的类型必须一致。3-8classProgram{staticvoidMain(string[]args){Console.WriteLine("按任意键退出,其它键继续…");while(Console.ReadKey().KeyChar!="Q"){Console.WriteLine("请输入本金:");doublex=double.Parse(Console.ReadLine());Console.WriteLine("请输入利率:");doubley=double.Parse(Console.ReadLine());Console.WriteLine("请输入存款年数:");doublez=double.Parse(Console.ReadLine());Console.WriteLine("本息合计为:");for(inti=0;i(ComplexNumberc1,ComplexNumberc2){doublea=c1.x*c1.x+c1.y*c1.y;doubleb=c2.x*c2.x+c2.y*c2.y;returna>b;}publicstaticbooloperator>=(ComplexNumberc1,ComplexNumberc2){returna==b||a>b;}publicstaticbooloperator<(ComplexNumberc1,ComplexNumberc2){return!(c1>=c2);}publicstaticbooloperator<=(ComplexNumberc1,ComplexNumberc2){return!(c1>c2);}}}4_5不能,因为this表示当前对象,而静态成员是通过类型本身而非对象来访问的。 4_6如果字符串格式错误的几率很小,使用Parse方法具有更高的效率;否则应选用TryParse方法来提高程序的可靠性。4_7略4_8publicintGetAge(DateTimebirthday){inty=DateTime.Year,m=DateTime.Month,d=DateTime.Day;if(d=size)free-=size;elseConsole.WriteLine("剩余空间不足!");} publicvirtualvoidDelete(floatsize){if(free+size<=total)free+=size;}}publicclassHardDisk{publicHardDisk(floatsize){this.total=this.free=size;}}publicclassFlashDisk{publicFlashDisk(){this.total=this.free=64000;}}publicclassCDROM{publicoverridevoidDelete(floatsize){Console.WriteLine("光盘不可删除!");}}5_6//抽象类:图形ShapepublicabstractclassShape{publicabstractdoublePerimeter{get;}publicabstractdoubleArea{get;}}//派生类:圆形CirclepublicclassCircle:Shape{privatedoubler;publicdoubleR;{get{returnr;}set{r=value;}}publicoverridedoublePerimeter{get{return6.28*r;}}publicoverridedoubleArea {get{return3.14*r*r;}}publicCircle(doubler){this.r=r;}}publicclassRectangle:Shape{privatedoublea,b;publicdoubleA;{get{returna;}set{a=value;}}publicdoubleB;{get{returnb;}set{b=value;}}publicoverridedoublePerimeter{get{return2*(a+b);}}publicoverridedoubleArea{get{returna*b;}}publicRectangle(doublea,doubleb){this.a=a;this.b=b;}}5_7在新类型中定义原结构类型的字段成员,通过该字段来调用结构的成员功能。5_8略5_9略Chapter66_1(1)定义委托原型,其签名应与要封装的方法保持一致。(2)定义委托类型的变量。(3)使用new关键字创建委托对象,并将要封装的方法名作为参数传递给构造函数。(4)通过委托变量来调用方法。6_2publicstaticvoidCompare(Students1,Students2){CompareFunctioncompare=newCompareFunction(CompareGrade);intx=compare(s1,s2); if(x==0){compare=CompareGrade;x=compare(s1,s2);if(x==0){compare=CompareGrade;x=compare(s1,s2);}}returnx;}publicstaticvoidSortAndPrint(Student[]students){for(inti=students.Length-1;i>0;i--)for(intj=0;j0){Students=students[j];students[j]=students[j+1];students[j+1]=s;}foreach(Studentsinstudents)Console.WriteLine(s);}6_3publicstaticvoidWriteDelegateInfo(Delegatedg){if(dg==null)return;Console.WriteLine("MethodName:{0}",dg.Method.Name);Console.WriteLine("MethodBelongType:{0}",dg.Method.DeclaringType);Console.WriteLine("Target:{0}",dg.Target);foreach(Delegatedgindg3.GetInvocationList()){Console.WriteLine(dg.Method);Console.WriteLine(dg.Target);}}6_4输出为:2,3,46_5匿名方法可以把一段代码直接作为参数使用,而无需显式地定义方法的原型。通过捕获外部变量,匿名方法还能够实现与外部程序的状态共享。这不仅能够简化程序,提高了代码的可维护性,还大大方便了程序中的各种计算。6_6事件是委托类型的对象,事件的触发方法是该对象的客户,而事件的处理方法是该对象提供的服务。6_7旅行团所关联的导游和负责业务员是明确的,可以在改变状态的方法代码中访问这些导游和业务员对象。而旅行团所关联的游客可能不断变化,采用发布/订阅方式能够方便地通知所有绑定的游客。6_8略Chapter77_1可从以下几方面考虑: (1)合理布局:在左上方或正上方提供车次和站名的输入控件,在中央显示查询结果。(2)方便导航:在查询结果中,通过单击车次和站名可直接显示相关信息。(3)简化输入:允许用户通过简拼或双拼等方式来输入中文站名。(4)撤销和恢复:允许用户回退到上次查询。(5)等待响应:查询时间较长时,显示等待光标,还可先显示部分查询结果。7_2对于不常用的字体族,创建其Font对象时要先检查用户计算机上是否安装了该字体。必要时可随程序安装字体。7_3在窗体尺寸改变事件中,通过Form对象的Height属性来进行控制。7_4通过文本框的KeyPress事件来进行控制:voidtextBox1_KeyPress(objectsender,KeyPressEventArgse){intch=e.KeyChar;if(ch<48||ch>57&&ch!=8)e.Handled=false;}7_5略7_6如果增加之后的数值超过控件的Maximum,第二行代码执行后会发生异常,而第一行代码会使控件中的数值等于Maximum。7_7略7_8提示:可参考MSDN帮助中的Control控件文档。7_9主要方面有:(1)业务对象与窗体界面绑定,通常是在窗体类中定义一个业务对象类型的字段成员,通过窗体初始化事件的处理代码来将对象信息显示在窗体控件中。(2)在保存对象信息时,通常要检查窗体控件中对应的输入信息是否完整和合法,否则应要求用户重新输入。(3)如果要在不同的窗体间传递对象,那么可将对象变量作为目标窗体的构造函数参数,通过其构造函数来初始化对应的对象字段。(4)如果多个窗体共享一个对象信息,那么在其中一个窗体修改了对象信息后,应及时更新其它窗体的显示内容。Chapter88_1以1000000以内的int值为例:staticvoidMain(){FileStreamfs1=newFileStream("num.txt",FileMode.Create);for(inta=1,b=1;a<=1000000;a+=b){intt=b;b=a;a=t;intx=a/(2<<24);fs1.WriteByte((byte)x);//写入25~32位a-=x;x=a/(2<<16);fs1.WriteByte((byte)x);//写入17~24位a-=x;x=a/(2<<8);fs1.WriteByte((byte)x);//写入9~16位a-=x; fs1.WriteByte((byte)x);//写入1~8位}fs1.Position=0;Console.Write("请输入要读取的数列项:");inti=int.Parse(Console.ReadLine());fs1.Position=4*i;inty=16777216*fs1.ReadByte()+65536*fs1.ReadByte()+256*fs1.ReadByte()+fs1.ReadByte();Console.WriteLine("数列项为:"+y);fs1.Close();}8_2提示:创建一个文本文件,在窗体的关闭事件中向文件写入当前时间,在窗体的启动事件中读取上次写入时间。8_3在控制台逐行依次输出48~578_4二进制方式对文件的存取效率较高,但编程更为复杂,需要处理字节类型与其它各种类型之间的转换。文本方式存取文件速度较慢,占用的磁盘容量也较大,但编程更为简单,只需要把各种类型都按字符串格式处理即可。8_5略8_6应在显示对话框之前设置的属性主要有:Filter、FilterIndex、InitialDirectory、RestoreDirectory、Multiselect、OverwritePrompt;之后设置的属性主要有FileName有FileNames。8_7在写入每个对象时,应首先将对象的类型名写入文件;在读取文件时,首先读取类型名,再根据不同的类型来使用构造函数创建对象。8_8在写入文件流时,可通过一个密钥字符来对文件的每个字节进行加密,即将字节与密钥字符进行与或运算后写入文件,读取时再与密钥字符进行一次与或运算来进行解密:publicvoidSave(BinaryWriterwriter,charkey){char[]chs=newchar[_username.Length];for(inti=0;i列表对象,将元素集合作为参数传递给列表对象的构造函数,而后调用列表对象的Sort方法进行排序。10_6略10_7包括二叉树节点类型BTNode和二叉树类型BinaryTree两部分,参考代码如下。//////二叉树节点类型 ///publicclassBTNode{privateobjectvalue;privateBTNodeleft,right;publicobjectValue{get{returnthis.value;}set{this.value=value;}}publicBTNodeLeft{get{returnleft;}set{left=value;}}publicBTNodeRight{get{returnright;}set{right=value;}}publicBTNode(objectobj){value=obj;}}//////二叉树类型///classBinaryTree:ICollection{privateBTNoderoot;publicBTNodeRoot{get{returnroot;}}publicintCount{get{returnPreTraverse(root).Length;}}privateBinaryTree(){this.root=null;}publicBinaryTree(objectobj){this.root=newBTNode(obj);}publicBinaryTree(BTNoderoot){this.root=root;} publicvoidCopyTo(Arrayarray,intindex){PreTraverse(root).CopyTo(array,index);}IEnumeratorIEnumerable.GetEnumerator(){returnPreTraverse(root).GetEnumerator();}boolICollection.IsSynchronized{get{returnfalse;}}objectICollection.SyncRoot{get{returnnull;}}publicstaticobject[]PreTraverse(BTNodenode)//前序遍历{if(node==null)returnnull;ArrayListnodes=newArrayList();nodes.Add(node.Value);if(node.Left!=null)nodes.AddRange(PreTraverse(node.Left));if(node.Right!=null)nodes.AddRange(PreTraverse(node.Right));returnnodes.ToArray();}publicstaticobject[]InTraverse(BTNodenode)//中序遍历{if(node==null)returnnull;ArrayListnodes=newArrayList();if(node.Left!=null)nodes.AddRange(InTraverse(node.Left));nodes.Add(node.Value);if(node.Right!=null)nodes.AddRange(InTraverse(node.Right));returnnodes.ToArray();}publicstaticobject[]PostTraverse(BTNodenode)//后序遍历{if(node==null)returnnull;ArrayListnodes=newArrayList();if(node.Left!=null)nodes.AddRange(PostTraverse(node.Left));if(node.Right!=null)nodes.AddRange(PostTraverse(node.Right));nodes.Add(node.Value);returnnodes.ToArray(); }publicstaticBinaryTreeEmptyBinaryTree{get{returnnewBinaryTree();}}}classProgram{staticvoidMain(){BinaryTreetree1=newBinaryTree(1);inti=1;BTNoder=tree1.Root;while(i<100){r.Left=newBTNode(i*2);r.Right=newBTNode(i*3);if(i%2==1){r=r.Left;i=i*2;}else{r=r.Right;i=i*3;}}object[]result=BinaryTree.PreTraverse(tree1.Root);Console.WriteLine("前序遍历:");foreach(objectobjinresult)Console.Write(obj.ToString()+",");Console.WriteLine("n中序遍历:");result=BinaryTree.InTraverse(tree1.Root);foreach(objectobjinresult)Console.Write(obj.ToString()+",");Console.WriteLine("n后序遍历:");result=BinaryTree.PostTraverse(tree1.Root);foreach(objectobjinresult)Console.Write(obj.ToString()+",");}}10_8略Chapter1111_1略11_2泛型类A中的嵌套类型B使用的类型参数S在A中没有定义,应将其改为B11_3输出内容如下:2:A"sSystem.Int322:B"sSystem.Int322.5:B"sSystem.Double 2.5:A"sSystem.Double11_4略11_5staticvoidMain(){Listl1=newList();l1.Add("王小红");l1.Add("周军");l1.Insert(0,"方小白");l1.Add("Smith");l1.Insert(1,"Jerry");Console.WriteLine("排序前:");foreach(stringsinl1)Console.Write(s+"");l1.Sort();Console.WriteLine("n排序后:");foreach(stringsinl1)Console.Write(s+"");}11_6提示:将二叉树节点类型BTNode改为泛型类型BTNode,其value字段/Value属性类型由object改为T,再修改相应的前序、中序和后序遍历等方法代码:publicstaticT[]PreTraverse(BTNodenode)//前序遍历{if(node==null)returnnull;Listnodes=newList();nodes.Add(node.Value);if(node.Left!=null)nodes.AddRange(PreTraverse(node.Left));if(node.Right!=null)nodes.AddRange(PreTraverse(node.Right));returnnodes.ToArray();}publicstaticT[]InTraverse(BTNodenode)//中序遍历{if(node==null)returnnull;Listnodes=newList();if(node.Left!=null)nodes.AddRange(InTraverse(node.Left));nodes.Add(node.Value);if(node.Right!=null)nodes.AddRange(InTraverse(node.Right));returnnodes.ToArray();}publicstaticT[]PostTraverse(BTNodenode)//后序遍历{if(node==null)returnnull;Listnodes=newList();if(node.Left!=null)nodes.AddRange(PostTraverse(node.Left));if(node.Right!=null) nodes.AddRange(PostTraverse(node.Right));nodes.Add(node.Value);returnnodes.ToArray();}11_7略Chapter1212_1如果只声明了可空类型的变量而没有进行赋值,那么访问其HasValue属性和Value属性都会引发异常。如果可空类型的变量值为null时,那么访问其Value属性会引发异常。12_2输出依次为:null,0,null12_3参考代码如下:publicIEnumeratorGetEnumerator()//默认遍历器:前序遍历{BTNodenode=root;Stack>stack=newStack>();while(node!=null||stack.Count>0){while(node!=null){yieldreturnnode.Value;if(node.Right!=null)stack.Push(node.Right);node=node.Left;}if(stack.Count>0)node=stack.Pop();}}publicIEnumerableInOrderEnumerator()//中序遍历{BTNodenode=root;Stack>stack=newStack>();while(node!=null||stack.Count>0){while(node!=null){stack.Push(node);node=node.Left;}if(stack.Count>0){node=stack.Pop();yieldreturnnode.Value;node=node.Right;}}}12_4以BreakingEnumerator为例:publicclassBreakingEnumerator:IEnumerator{privateintcurrent;internalstring[]phones; publicstringCurrent{get{returnphones[current];}}objectIEnumerator.Current{get{returnphones[current];}}publicBreakingEnumerator(string[]phones){this.phones=phones;current=-1;}publicboolMoveNext(){if(phones[++current]==null)returnfalse;elsereturntrue;}publicvoidReset(){current=-1;}voidIDisposable.Dispose(){}}12_58次12_6略12_7略Chapter1313_1提示:为窗体添加一个字段angle,用于记录按钮运动方向与x轴正向的夹角;按钮单位时间在x轴和y轴上移动的分量分别为cos(angle)和sin(angle)(注意角度与弧度的换算);当按钮移动到窗体左右或上下边界时,角度自动发生折转:voidtimer1_Tick(objectsender,EventArgse){button1.Left+=(int)(10*Math.Cos(angle*Math.PI/180));button1.Top+=(int)(10*Math.Sin(angle*Math.PI/180));if(button1.Left<=0||button1.Right>=this.ClientSize.Width)angle=(180-angle);if(button1.Top<=0||button1.Bottom>=this.ClientSize.Height)angle=360-angle;}13_2略13_3提示:存储时应按树型视图的层次顺序将节点内容依次写入文件,载入时应先读取高层节点内容,再读取低层节点内容并最为子节点添加。13_4ListView是对列表框控件ListBox的扩展,它能够以文字、图标和多列格式显示列表内容。TreeView控件显示一个树型结构,能够从顶层节点逐步展开至叶节点 DataGridView是一个标准的数据网格控件。ListView显示简单列表数据最为方便,采用多列格式显示二维数据集也比较高效,但修改数据较为复杂,需要通过各种事件处理代码来进行控制。对于简单层次嵌套型数据,TreeView控件显示起来最为直观。而DataGridView功能最为强大,能够显示和处理各种集合数据,特别是能够与数据集方便地进行绑定,但占用系统资源较多。一般而言,需要经常修改的动态数据集合更适合采用DataGridView控件,而ListView和TreeView显示静态数据更为高效。13_5publicpartialclassForm1:Form{privateSystem.Drawing.Printing.PrintDocumentpd;publicForm1(){InitializeComponent();this.Paint+=newPaintEventHandler(Form1_Paint);pd=newSystem.Drawing.Printing.PrintDocument();pd.PrintPage+=newSystem.Drawing.Printing.PrintPageEventHandler(pd_PrintPage);}voidForm1_Paint(objectsender,PaintEventArgse){e.Graphics.FillEllipse(Brushes.Blue,0,0,this.ClientSize.Width,this.ClientSize.Height);e.Graphics.Dispose();}privatevoidForm1_Resize(objectsender,EventArgse){this.Invalidate();}voidpd_PrintPage(objectsender,System.Drawing.Printing.PrintPageEventArgse){e.Graphics.FillEllipse(Brushes.Blue,e.PageBounds);e.Graphics.Dispose();}privatevoidForm1_DoubleClick(objectsender,EventArgse){PrintDialogdlg1=newPrintDialog();dlg1.Document=pd;if(dlg1.ShowDialog()==DialogResult.OK)pd.Print();}}13_6提示:综合使用Timer控件的Tick时间和窗体的Paint事件,在Timer.Tick时间中定期修改颜色。13_7提示:Graphics是对计算机绘图设备的封装,.NET中为不同的设备对象创建Graphics对象的方法采用了“创建者”的设计模式,通过Graphics绘制各种图形应用了“装饰者”的设计模式,这有效地降低了对象之间的耦合程度,提高了程序的抽象性和灵活性。 13_8略Chapter1414_1Windows窗体运行在客户端;而Web窗体由服务器端生成后发送到客户端,并将用户交互结果返回到服务器端进行处理。14_2通过HttpRequest的Path属性获取服务器上的虚拟路径。14_3(1)字符串参数:使用Response.Redirect转到指定页面,并将参数附加在页面地址的“?”号之后;在新页面中通过Request.QueryString方法解析参数。适合传输一个或几个简单类型数据,安全性差。(2)Application:在一个网页代码中向HttpApplicationState的指定键中写入值,在另一个网页中读出。适合于多个网页共享全局变量,但在应用程序结束后失效。(3)Session:在一个网页代码中写入会话内容,在另一个网页中读出。读写方便,安全性好,但只在会话有效范围内可用。(4)ViewState:在一个网页代码中写入状态视图,在另一个网页中读出。适合与页面控件相关的数据传送,但安全性较低,且数据量大时会影响页面发送效率。(5)Cache:使用服务器缓存,适合大批量数据,但可能存在延迟。(6)Cookies:在一个网页代码中写入客户端Cookies,在另一个网页中读出。特点是读写方便、效率高,但Cookies数量和内容大小受限,且可能被客户端禁用。14_4ListView、TreeView和DataGridView略14_5RadioButtonList和CheckBoxList等Web服务器控件提供了AutoPostBack属性,其值为true时用户改变控件中的选项将直接导致窗体被回送到服务器。这样在网页的初始化事件中,应通过IsPostBack属性来判断页面是首次加载、还是响应选项改变事件,从而选择不同的初始化操作。14_7略14_8略14_9提示:可参考MSDN帮助中的Control控件文档。Chapter1515_1略15_2略15_3参考T-SQL语句:(1)SELECTStudent.*FROM[Student],[Score]WHERE[Student.ID]=[Score.StudentID]AND[Score.Math]>=60AND[Score.English]>=60AND[Score.Computer]>=60(2)SELECTTOP1Student.*FROM[Student],[Score]WHERE[Student.ID]=[Score.StudentID]ORDERBY[Score.Math]+[Score.English]+[Score.Computer]DESCSELECTTOP1Student.*FROM[Student],[Score]WHERE[Student.ID]=[Score.StudentID]ORDERBY[Score.Math](3)SELECTTOP1Student.*FROM[Student],[Score]WHERE[Student.ID]=[Score.StudentID]GROUPBY[Student.Class]ORDERBY[Score.Math]+[Score.English]+[Score.Computer]DESCSELECTTOP1Student.*FROM[Student],[Score]WHERE[Student.ID]=[Score.StudentID]GROUPBY[Student.Class]ORDERBY[Score.Math]15_4提示:使用DataTable对象的Select方法,命令内容与上面基本相同。15_5略 15_6略15_7略'