C#面向对象程序设计(第2版)(txt+pdf+epub+mobi电子书下载)


发布时间:2020-11-25 23:13:23

点击下载

作者:郑宇军

出版社:人民邮电出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

C#面向对象程序设计(第2版)

C#面向对象程序设计(第2版)试读:

第2版前言

自2009年6月本书第1版出版以来,颇受广大读者的欢迎,也有幸被许多老师选为程序设计专业教材。经过3年多的时间,编者结合教学实践和软件开发中的经验体会、C#语言的最新升级以及许多读者热情的反馈建议,对原书进行了系统的修订。

这次修订保留了原教材特点,坚持以面向对象的软件工程思想为主线、紧密贴合实际应用需求;同时增加了一些新的知识点,加强了教材内容的新颖性和趣味性,以便进一步提升教学效果。修改的主要方面包括:(1)以C#4.0/4.5版本为主进行讲解(但语言的核心要素并没有根本变化,新版本的优势主要体现在应用的多样性和开发的方便性上)。(2)在第6章中增加了对Lambda表达式的介绍。(3)将原来的第7章和第13章压缩合并在一起,在新的第13章中对 WPF(Windows Presentation Foundation)进行了较为细致的讲解。(4)在第15章中新增了“LINQ 对象数据查询”一节,使读者能够对 LINQ数据访问技术有一个初步的了解。(5)新增了第16章“Silverlight客户端应用程序”,对Silverlight富客户端开发技术进行了深入讲解。

本书配套的教学课件和案例程序代码也进行了相应的升级,有关内容可在人民邮电出版社网站上进行下载。

本书第1章由王侃执笔,第2章和第15章由杨军伟执笔,第3章~第14章和第16章由郑宇军执笔,吴晓蓓、凌海风、江勋林、郑艳华、宋琴等也参与了本书的部分文字编写工作。全书由郑宇军统稿。

此次编写工作得到了我校王卫红老师的悉心指导和帮助。在C#程序设计课程教学实践中,与简琤峰老师和王松老师的经验交流使编者受益良多。同时,感谢我校计算机学院09级的徐静、张璐滢、何俊丽、王岳春、顾唯超、诸伊娜等同学,他们在学习开发过程中的创造性给了编者很多启发。

尽管我们做了最大的努力,书中的不足与疏漏之处仍在所难免,恳请广大读者批评指正。我们的E-mail地址是:bookzheng@yeah.net(邮件主题请注明“CSharp程序设计”)。编者2012年8月于浙江工业大学 郁文楼第1章面向对象程序设计概述

本章简要地回顾了计算机程序设计语言和软件开发方法的发展历程,并由此引出了面向对象的基本思想、概念和方法。掌握这些基本知识能为深入学习C#面向对象程序设计打下良好的基础。1.1 计算机程序设计语言

人类使用自然语言,而计算机执行的是机器指令;程序设计语言是人与计算机之间进行交流的工具,它定义了一套代码规则,程序设计人员遵循这些规则所编写出来的程序可被翻译成计算机能够“理解”的形式。

程序设计语言可以分为低级语言和高级语言。低级语言包括机器语言和汇编语言,使用它们进行编程需要对机器结构有深入的了解,而且代码晦涩难懂、不利于人们的理解和交流。高级语言则更加接近自然语言,比较符合人们的思维方式,因此大大提高了程序设计的效率,并使得人们通过“阅读程序文本”来理解“计算过程”成为可能。高级语言程序在计算机上有两种处理方式:一是由专门的解释程序来直接解释执行高级语言代码,二是由专门的编译程序将其翻译为低级语言代码而后执行。目前在程序设计的各个主要领域,高级语言已基本上取代了低级语言。

Fortran语言是第一个被广泛使用的高级语言,其程序由一个主程序和若干个子程序组成,通过将不同的功能分配到独立的子程序中,能够有效地实现程序的模块化。20世纪七八十年代非常流行的Pascal语言提供了丰富的数据类型和强有力的控制结构,使用它能够方便地编写结构化的应用程序,其程序结构中的一个模块就是一个过程,因此也被称为面向过程的语言。当然,最为流行的结构化程序设计语言莫过于C语言,它兼顾了诸多高级语言的特点,同时还提供了指针和地址等低级操作的能力,因此既适合于开发应用程序,又适合于开发系统程序,此外它还有良好的可移植性,成为程序设计语言诞生以来最为成功的范例之一。

简而言之,结构化程序设计采用自顶向下、分而治之的方法,对目标系统进行功能抽象和逐步分解,直至每个功能模块都能以一个过程或函数来实现为止。这样就将复杂系统划分为一系列易于控制和处理的软件模块,其特点是结构良好,条理清晰,功能明确。对于需求稳定、算法密集型的领域(如科学计算领域),上述方法是有效并适用的。

随着信息技术的飞速发展,计算机软件从单纯的科学和工程计算渗透到社会生活的方方面面,软件的规模也越来越大,复杂性提高,此时结构化方法逐步暴露出诸多问题和缺陷,这主要体现在:

•功能与数据相分离,使用的建模概念不能直接映射到问题领域中的对象,不符合人们对现实世界的认识和思维方式。

•自顶向下的设计方法,限制了软件模块的可复用性,降低了开发效率。

•当系统需求发生变化时,系统结构往往需要大幅调整,特别是对于较复杂的系统,维护和扩展都变得非常困难。

为了解决上述问题,一种全新的、强有力的软件开发方法——面向对象(Object Oriented, OO)的方法应运而生。它是在结构化等传统方法的基础上发展起来的,也使用抽象和模块化等概念;但和传统方法相比,其根本性的变化在于:不再将软件系统看成是工作在数据上的一系列过程或函数的集合,而是一系列相互协作而又彼此独立的对象的集合。这不仅更为符合人们的思维习惯,有助于保持问题空间和解空间在结构上的一致性,同时能够有效控制程序的复杂性,提高软件的生产效率。近二十年来,面向对象的方法学得到了迅速发展和广泛应用,Java、C++、C#等面向对象的程序设计语言也成为了当今世界上计算机软件的主流开发语言。1.2 面向对象的基本概念

本节介绍面向对象技术中一些最为基本的概念。1.2.1 对象

客观世界中的事物都是对象(Object),这既包括有形的物理对象(如一个人、一只狗、一本书等),也包括抽象的逻辑对象(如一个几何图形、一项商业计划等)。对象一般都有自己的属性(Attribute),而且能够执行特定的操作(Operation)。例如,一个人可以描述为“姓名张三,身高170,体重 65”,这里的“姓名”、“身高”、“体重”就是对象的属性,而“张三”、“170”、“65”则是对应的属性值;该对象还可以执行“走路”、“看书”等操作。属性用于描述对象的静态特征,而操作用于描述对象的动态特征。

在面向对象的模型中,软件对象就是对客观世界中对象的抽象描述,是构成软件系统的基本单位。但软件对象不应也不可能描述现实对象的全部信息,而只应包含那些与问题域有关的属性和操作。例如,在一个学籍管理系统中,通常会关心每个“学生”对象的“姓名”、“学号”、“专业”等属性信息,而他们的“发型”、“鞋号”等信息则不属考虑范围。1.2.2 类

类(Class)是指具有相同属性和操作的一组对象的集合,它描述的不是单个对象而是“一类”对象的共同特征。例如在学籍管理系统中可以定义“学生”类,而“张三”、“李明”、“王娟”这些学生就是属于该类的对象,或者叫做类的实例(Instance);它们都具有该类的属性和操作,但每个对象的属性值可以各不相同。

类是面向对象技术中最重要的结构,它支持信息隐藏和封装,进而支持对抽象数据类型(Abstract Data Type,ADT)的实现。信息隐藏是指对象的私有信息不能由外界直接访问,而只能通过该对象公开的操作来间接访问,这有助于提高程序的可靠性和安全性。例如“学生”类可以有“生日”和“年龄”这两个属性,那么可以把它们都定义为私有的,不允许直接修改;再定义一个根据生日计算年龄的私有操作,以及一个修改生日的公共操作,这样用户就只能通过对象的生日来间接修改其年龄,从而保证其年龄和生日的合法性。

类将数据和数据上的操作封装为一个有机的整体,类的用户只关心其提供的服务,而不必了解其内部实现细节。例如对于“借书证”类的“刷卡”操作,用户可以只关注该操作返回的借书人信息(如借书权限、是否欠费等),而不去管磁条中是怎样存储借书人的有关信息的。1.2.3 消息和通信

对象具有自治性和独立性,它们之间通过消息(Message)进行通信,这也是对客观世界的形象模拟。发送消息的对象叫做客户(Client),而接收消息的对象叫做服务器(Server)。按照封装原则,对象总是通过公开其某些操作来向外界提供服务;如果某客户要请求其服务,那么就需要向服务器对象发送消息,而且消息的格式必须符合约定要求。消息中至少应指定要请求的服务(操作)名,必要时还应提供输入参数和输出参数。例如,某“学生”对象需要办理借书证,那么就要请求“图书馆”对象的“办理图书证”服务,并在消息中提供自己的姓名、学号等消息;“图书馆”对象检查这些消息合格后,创建一个新的“借书证”对象并返回给该学生。1.2.4 关系

在很多情况下,单个对象是没有作用的。例如“轮子”、“车厢”、“发动机”等对象单独放在那里都没有什么意义,而只有将它们组成一个“汽车”对象才能发挥各自的作用。再如“学生”对象也不能是孤立的,而是要和“班级”、“老师”、“考试”等对象进行交互才能有意义。对象之间的关系可在类级别上进行概括描述,典型的有以下几种。

•聚合(Aggregation):一个对象是另一个对象的组成部分,也叫部分—整体关系,如“轮子”与“汽车”的关系,“学生”和“班级”的关系等。

•依赖(Dependency):一个对象对另一个对象存在依赖关系,且对后者的改变可能会影响到前者,如“借书证”对象依赖于某个“学生”对象,当“学生”对象不存在了(如该学生毕业或退学),相应的“借书证”对象也应被销毁。

•泛化(Generalization):一个对象的类型是另一个对象类型的特例,也叫特殊—一般关系,其中特殊类表示对一般类内涵的进一步细化,如“学生”类可进一步细化为特殊的“本科生”和“研究生”类。从泛化关系可以引出面向对象方法中另一个重要概念——继承。

•一般关联(Association):对象之间在物理或逻辑上更为一般的关联关系,主要是指一个对象使用另一个对象的服务,如“老师”和“学生”之间的教学关系。根据语义还可将关联关系分为多元关联和二元关联,二元关联还可进一步细分为一对一关联、一对多关联以及多对多关联等。聚合和依赖有时也被视为特殊的关联关系。

上述 4 种关系的简单示例如图 1-1所示。图1-1 聚合、依赖、泛化和关联关系示例1.2.5 继承

在泛化关系中,特殊类可自动具有一般类的属性和操作,这叫做继承(Inheritance);而特殊类还可以定义自己的属性和操作,从而对一般类的功能进行扩充。例如“学生”类可以从“人”这个类中继承,这样就继承了“人”的“姓名”、“身高”等属性,而“学号”、“专业”等则是“学生”类自己特有的属性。在类的继承结构中,一般类也叫作基类或父类,特殊类也叫作派生类或子类。

继承的概念是从生物学中借鉴而来的,它可以具有多层结构。例如,动物可分为脊椎动物和无脊椎动物,脊椎动物又可分为哺乳动物、鱼类、鸟类、爬行动物、两栖动物等,这种划分可以持续很多层。在分类过程中,低级别的类型通常继承了高级别类型的基本特征。图1-2所示为这一简单的动物继承关系。不过,在实际软件系统的建模过程中,继承的层次结构不宜过细过深,否则会增加理解和修改的难度。图1-2 动物的继承关系图

继承具有可传递性。例如“学生”类从“人”类继承,“研究生”类再从“学生”类继承,那么“本科生”和“研究生”类也就自动继承了“人”的“姓名”、“身高”等属性。这样派生类就能够享受其各级基类所提供的服务,从而实现高度的可复用性;当基类的某项功能发生变化时,对其的修改会自动反映到各个派生类中,这也提高了软件的可维护性。

自然界中还存在一种多继承的形式,例如,鸭嘴兽既有鸟类的特征又有哺乳动物的特征,那么可以把它看成是鸟类和哺乳动物共同的派生类;再如一名在职研究生可能同时具有老师和学生的身份。在面向对象的软件开发中,多继承具有较大的灵活性,但同时也会带来语义冲突、程序结构混乱等问题。目前,C++和Eiffel等语言支持多继承,而Java和C#等则不支持,但它们可通过接口等技术来间接地实现多继承的功能。1.2.6 多态性

多态性(Polymorphism)是指同一事物在不同的条件下可以表现出不同的形态。在面向对象的消息通信时,发送消息的对象只需要确定接收消息的对象能够执行指定的操作,而并不一定要知道接收方的具体类型;接收到消息之后,不同类型的对象可以作出不同的解释,执行不同的操作,从而产生不同的结果。例如,学籍管理系统在每学期开始时会要求每个学生对象执行“选课”操作,但系统在发送消息时并不需要区分学生的具体类型是本科生还是研究生,而不同类型的学生会自行确定自己的选课范围,因为“本科生”类和“研究生”类会各自定义不同的“选课”操作。多态性特征能够帮助我们开发灵活且易于修改的程序。1.2.7 接口和组件

随着软件规模和复杂度的不断增长,现代软件开发越来越强调接口(Interface)和组件(Component)技术,而接口也已成为面向对象不可或缺的重要元素。组件是指可以单独开发、测试和部署的软件模块,接口则是指对组件服务的抽象描述。一个组件中可以只有一个类,也可以包含多个类。

接口是一种抽象数据类型,它所描述的是功能的“契约”,而不考虑与实现有关的任何因素。例如,可以定义一个名为“图书借阅”接口,并规定其中包括“图书目录查询”、“借书”和“还书”这三项功能。一个类如果声明支持某接口,它就必须支持接口契约中规定的全部功能。例如“图书馆”类要声明支持“图书借阅”接口,它就至少要为“图书目录查询”、“借书”和“还书”这三项操作提供具体的实现机制。

接口一旦发布就不应再作修改,否则就会导致所有支持该接口的类型都变得无效。而组件一经发布,也不应取消它已声明支持的接口,而是只能增加新的接口。例如“图书借阅”接口发布后,我们不能简单地试图为该接口增加一项“图书复印”功能,否则很多已支持该接口的类型就会出错;更合理的方式是定义一个新的“图书复印”接口,那些具有复印能力的类型可以声明支持这个新接口,而不具备复印功能的类型则保持不变。

对于服务的使用方(客户)而言,它既不关心服务提供者的实际类型,也不关心实现服务的具体细节,而只需要根据接口去查询和使用服务即可。例如读者可以向任何一个声明支持“图书借阅”接口的对象发送图书查询请求,并在查到自己所需图书后发送借阅请求,而不必考虑服务的提供者究竟是图书馆、书店还是别的什么机构。接口将功能契约从实现中完全抽象出来,能够有效地实现系统职责分离,同时弥补继承和多态性的功能不足,进而实现良好的系统设计。1.3 面向对象的开发方法

从20世纪80年代开始,面向对象技术得到了飞速的发展,业界也涌现了一系列面向对象的软件开发方法学,其中代表性的有Booch方法、Wirfs-Brock的责任驱动设计方法、Rambaugh的对象模型技术、Coad/Yourdon分析和设计方法、Jacobson的面向对象软件工程方法等。为了避免不同符号所引起的混乱,Booch、Rambaugh 和 Jacobson 等共同参与制定了统一建模语言 UML(Unified Modeling Language),采用统一的概念和符号来描述对象模型,支持软件开发的全过程。目前,UML已成为世界通用的面向对象的建模语言,适用于各种开发方法。1.3.1 面向对象的分析

面向对象的分析(Object Oriented Analysis,OOA)就是运用面向对象的方法对目标系统进行分析和理解,找出描述问题域和系统责任所需要的对象,定义对象的基本框架(包括对象的属性、操作以及它们之间的关系),最后得到能够满足用户需求的系统分析模型。OOA 主要有以下 5项任务。(1)识别问题域中的对象和类。通过对问题域和系统责任的深入分析,尽可能地找出与应用有关的对象和类,并从中筛选出真正有用的对象和类。(2)确定结构。找出对象和类中存在的各种整体—部分结构和一般—特殊结构,并进一步确定这些结构组合而成的多重结构。(3)确定主题。如果系统包含大量的对象和类,那么可划分出不同的应用主题域,并按照主题域对分析模型进行分解。(4)定义属性。识别各个对象的属性,确定其名称、类型和限制,并在此基础上找出对象之间的实例连接。(5)定义服务。识别各个对象所提供的服务,确定其名称、功能和使用约定,并在此基础上找出对象之间的消息连接。

OOA的结果是系统分析说明书,其中包括使用类图和对象图等描述的系统静态模型,使用例图、活动图和交互图等描述的系统动态模型,以及对象和类的规约描述。模型应尽量与问题域保持一致,而不考虑与目标系统实现有关的因素(如使用的编程语言、数据库平台和操作系统等)。1.3.2 面向对象的设计

面向对象的设计(Object Oriented Design,OOD)是以系统分析模型为基础,运用面向对象的方法进行系统设计,解决与系统实现有关的一系列问题,最后得到符合具体实现条件的系统设计模型。OOD主要有以下4项任务。(1)问题域设计。对问题域中的分析结果作进一步的细化、改进和增补,包括对模型中的对象和类、结构、属性、操作等进行组合和分解,并根据面向对象的设计原则增加必要的新元素类、属性和关系。这部分主要包括以下设计内容:

•复用设计,即寻找可复用的类和设计模式,提高开发效率和质量。

•考虑对象和类的共同特征,增加一般类以建立共同协议。

•调整继承结构,如减少继承层次、将多继承转换为单继承、调整多态性等。

•改进性能,如分解复杂类、合并通信频繁的类、减少并发类等。

•调整关联关系,如将多元关联转换为二元关联、将多对多关联转换为一对多关联等。

•调整和完善属性,包括确定属性的类型、初始值和可访问性等。

•构造和优化算法。(2)用户界面设计。对软件系统的用户进行分析,对用户界面的表现形式和交互方式进行设计。这部分主要包括以下设计内容:

•用户分类。

•人机交互场景描述。

•系统命令的组织。

•详细的输入和输出设计。

•在需要时可增加用于人机交互的对象和类,并使用面向对象的方法对其进行设计。(3)任务管理设计。当系统中存在多任务(进程)并发行为时,需要定义、选择和调整这些任务,从而简化系统的控制结构。这部分主要包括以下设计内容:

•识别系统任务,包括事件驱动任务、时钟驱动任务、优先任务和关键任务等。

•确定任务之间的通信机制。

•任务的协调和控制。(4)数据管理设计。识别系统需要存储的数据内容和结构,确定对这些数据的访问和管理方法。这部分主要包括以下设计内容:

•数据的存储方式设计,目前主要有文件系统和数据库系统两种方式。

•永久性类(Persistent Class)的存储设计,包括其用于存储管理的属性和操作设计。

•永久性类之间关系的存储设计。

OOA和OOD之间不强调严格的阶段划分,设计模型是对分析模型的逐步细化,主要是在问题域和系统责任的分析基础上解决各种与实现有关的问题。OOA阶段一些不能确定的问题可以遗留到OOD阶段解决,开发过程中也允许存在反复和迭代。1.4 案例研究——旅行社管理系统的分析与设计

旅行社管理系统是为旅行社提供业务支持的信息系统。旅行社设计旅游线路,并推出各种类型的旅行团。游客可查询旅游信息并报名参加旅行团,旅行社根据报名情况组织发团。通过简要的分析,可知系统的基本功能需求包括:(1)旅行社设计旅游线路,每条旅游线路包含若干个旅游景点。(2)旅行社基于旅游线路定制旅行团。(3)游客上网查询旅游景点、线路和旅行团信息。(4)游客报名参加旅行团,旅行社业务员负责接受或拒绝报名申请。(5)满足条件后,旅行社为旅行团安排导游并发团。

在上述分析的基础上,可以找到一系列可能的对象,并将其抽象到不同的类。最为基本的类有以下几个:

•景点类Scene,具有景点名称、位置、种类、票价等属性。

•旅游线路类Line,具有线路名称、景点集合、用时等属性。

•旅行团类Tour,具有旅游线路、时间、等级、人数、价格、导游、游客等属性。

•游客类 Customer:具有游客姓名、身份证号、性别、生日等属性,还可以执行报名和取消报名等操作。

景点所在的位置应通过所属的省市来描述,那么需要定义Province和City类,它们和Scene类之间是聚合的关系。为了加强客户关系管理,旅行社还积极发展游客成为注册会员。为此可定义Customer的派生类Member,它在Customer的基础上增加了用户名、密码、会员积分等属性。

一个成熟的旅行社通常会有多个固定的组团方案,如每天一次的北京一日游、每周一次的四川三日游等。那么可以把这些方案抽象为一个Package类,由该类维护旅游线路、等级、价格等信息,这样基于同一方案的多个旅行团就可以共享这些信息,而每个旅行团对象只需要关心自己的时间、导游、游客等独立信息。图1-3所示为这些类之间的基本关联关系。图1-3 Scene、Line、Package、Tour、Customer等主要业务类的关系图

系统还需要提供旅行社的内部管理功能,那么可定义旅行社类TravelAgency,它具有名称、总经理、法人代表、通讯地址、电话等属性。为了对旅行社的职员进行管理,可将旅行社的所有职员抽象为一个Staff类,它具有姓名、身份证号、性别、年龄、学历等属性,不同类型的职员可定义为Staff的不同派生类,主要包括:

•导游类Guide,具有导游证号、导游证有效期等属性。

•业务员类Agent,负责处理游客报名、组团管理等操作。

•主管类Director,除处理旅行社业务外,还负责管理一般职员。

•经理类Manager,基本属性和Director相同,还可执行雇佣和解雇其他职员等操作。

另一些岗位(如前台、保安等)在系统中没有专门的功能,那么可作为一般Staff对待。系统所关心的职员类型的基本继承关系如图1-4所示。

上述类型都是旅行社管理系统的业务类,它们都不可避免地要使用到大量的通用数据类型,如整数、字符串、日期时间等,这大都可以在程序设计语言的类型系统中找到。系统所使用的用户界面中也会用到大量的控件类,如窗体、按钮、网页、图片等,这也主要由商业开发工具来提供。当然,随着开发过程的深入,还可能发现更多需要的类型,如酒店、机场、车站等,这里可将它们先记录为候选类。图1-4 旅行社及其职员类的关系图

从设计角度出发,整个旅行社管理系统可划分为以下3部分。

•业务类库:管理和维护上述基本业务类。

•旅行社网站:供游客进行旅游资讯查询、旅行团网上报名等操作。

•旅行社内部管理子系统:供旅行社职员进行线路、旅行团、游客等信息管理工作。

以上是旅行社管理系统的初步分析和设计结果,其具体内容将在本书后续章节中不断细化和完善。1.5 小结

本章介绍了面向对象程序设计的基本概念,它将客观世界中的事物建模为软件对象,具有相同属性和操作的一组对象可抽象为类,类之间的关联和继承等关系是面向对象软件系统设计的关键。1.6 习题

1.简述对象和类的概念,并说说类在软件系统设计中的重要性。

2.面向对象技术中的继承是指什么?试举例说明你在日常生活中看到的继承例子。

3.将图1-3和图1-4合并成为一个更为完整的关系图。

4.查阅有关统一建模语言UML的资料,初步了解UML与面向对象技术的关系。第2章C#和Visual Studio开发环境基础

本章从C#语言和.NET技术的概貌入手,依次介绍了C#程序的组成结构和Visual Studio开发环境,读者将从这里开始自己的C#程序开发之路。2.1 C#语言和.NET技术简介

C语言曾经是最为流行的一门结构化程序设计语言,C++则在C语言的基础上增加了对面向对象的支持。但严格来说,C++并不是完全面向对象的程序设计语言;为了和C语言相兼容,C++保留了许多低级特性,因此具有较大的灵活性和较强的底层控制能力。但它也导致了C++学习困难、程序过于复杂、安全性难以保证等问题。

正如低级语言被高级语言逐步取代一样,程序设计语言的发展就是不断增强抽象描述能力、屏蔽底层实现细节、提高软件生产率的过程。随着面向对象的优越性被广泛接受,人们需要更加符合现代软件开发要求的面向对象程序设计语言,C#因此应运而生。它汲取了C++、Java、Delphi等多种语言的精华,具有语法简洁、类型安全、完全面向对象等特点,自2000年一经推出便取得了巨大的成功。

C#语言简单易学,它将内存管理、设备驱动、控制优化等底层操作交由.NET Framework实现,这样开发人员就能够把注意力集中在问题域模型和程序逻辑上,而不必去关注过多的底层细节。概括地说,.NET是一个建立在开放网络协议和标准之上的计算平台,.NET Framework则是.NET平台上的基础编程框架,它由以下两部分组成。

•公共语言运行时(Common Language Runtime,CLR)。它提供了.NET应用程序的运行时环境,负责管理代码的执行、提供元数据类型支持和各种系统服务。

•.NET 类库。它定义了功能丰富的类型集合,能够为应用程序提供基本类型、通用数据结构、Windows和Web界面设计、数据库访问、XML Web Service、异常处理等各种组件服务。

.NET Framework支持C#、Visual Basic .NET、Visual C++ .NET等多种语言,这些高级语言代码会被编译为一种通用中间语言IL(Intermediate Language)代码,该语言类似于低级语言,但其代码与具体的硬件平台无关;之后CLR再针对特定的平台将IL程序翻译为机器指令,加载所需的资源并管理程序的执行。这也使得.NET平台上不同语言程序能够方便地进行通信,解决了困扰人们已久的多语言集成的难题。

随着语言的流行和用户的增加,C#也得到了不断的改进和完善。2005 年 C#升级到了 2.0 版本,其最大特点是增加了对泛型程序设计(Generic Programming)的支持。2008年C#推出3.5版,其中增加了 Lambda 表达式、隐式类型、扩展方法等特性,并支持一种新的面向对象的数据访问模型——LINQ(Language Integrated Query)模型。2010年C#推出4.0版,新增特性包括可选参数和命名参数、元组(Tuple)类型、动态绑定、逆变和协变等。目前C#语言的最新版本是4.5,其提供了增强的异步操作和国际化支持等功能。.NET Framework也随之进行了相应的版本升级,为.NET应用开发提供了更为有效的支持。2.2 C#程序的基本结构

下面先看一个非常简单的C#程序,它用于在屏幕输出一行文本“欢迎光临!”。

//程序P2_1

using System;

namespace P2_1

{

public class Program

{

public static void Main()

{

Console.WriteLine("欢迎光临!");

}

}

}

可在任何一种文本编辑器(如Windows记事本或Microsoft Word)中输入上述代码,将文件存为“P2_1.cs”(后缀名.cs表示C#源程序文件);而后打开命令行窗口,使用C#编译器csc.exe编译程序(必要时指定源文件所在的目录)就能生成的可执行文件P2_1.exe。程序的编译和运行结果如图2-1所示。图2-1 编译和执行C#程序P2_1

C#编译器csc.exe位于Windows目录下的\Microsoft.NET\Framework\v*.*子目录中,其中 v*.*表示.NET Framework 的版本号,如“C:\Windows\Microsoft.NET\Framework\v4.0.30319”。使用命令行编译时,可将该目录加入系统Path环境中。通过命令“csc/?”可以查看编译器使用选项的帮助信息,有关编译器更为详细的内容可参看MSDN帮助。

接下来分析一下该程序的基本结构。2.2.1 注释

程序P2_1的第1行以连续两个反斜杠“//”开头,表示程序的注释,那么在它同行右侧的内容会被编译器忽略,不对程序的运行产生任何影响。如果要写多行注释,可以每一行都以“//”开头,或是将所有注释内容都放在一对标记“/*”和“*/”之间,例如:

/*程序P2_1

该程序用于在屏幕输出一行文本“欢迎光临!”*/

但多行注释标签不可以嵌套。例如对于下面的代码,编译器会将第一行开头的“/*”到第二行末尾的“*/”之间的内容视为注释,第三行的标记“*/”视为非法代码:

/*程序P2_1

/*该程序用于在屏幕输出一行文本"欢迎光临!" */

*/

注释可以出现在程序代码的任何位置,主要用于对代码的功能和用途等进行描述,从而提高程序的可读性,便于理解和修改程序。优秀程序员都应当养成注释代码的良好习惯。2.2.2 命名空间

程序中常常需要定义很多的类型,为了便于类型的组织和管理,C#引入了命名空间的概念。一组类型可以属于一个命名空间,而一个命名空间也可以嵌套在另一个命名空间中,从而形成一个逻辑层次结构,这就好比目录式的文件系统组织方式。

程序P2_1的第2行通过关键字“using”引用了一个.NET类库中的命名空间“System”,之后程序就可以自由使用该命名空间下定义的各种类型。程序的第3行则通过关键字“namespace”定义了一个新的命名空间“P2_1”,在其后的一对大括号“{}”中定义的所有类型都属于该命名空间。

C#语言是大小写敏感的,比如关键字“using”不能写成“USING”,“namespace”不能写成“Namespace”。

命名空间的使用还有利于避免命名冲突。不同的开发人员可能会使用同一个名称来定义不同的类型,这在程序相互调用时就会产生混淆,而将这些类型放在不同的命名空间中就可以解决此问题。2.2.3 类型及其成员

在C#语言中,类是最为基本的一种数据类型,类的属性叫做“字段”(Field),类的操作叫做“方法”(Method)。类使用关键字“class”来定义,程序 P2_1 就定义了一个名为“Program”的类,并为其定义了一个方法“Main”,在其中执行文本输出的功能:

public static void Main()

{

Console.WriteLine("欢迎光临!");

}

这里Main方法的功能是通过调用Console类的WirteLine方法来完成的,方法的输入参数是用一对双引号括起来的字符串,表示要输出的文本内容。如果要显式定义字符串对象,那么Main方法中的代码可改写为如下内容,其中string表示字符串类型,而s是该类型的一个对象(也叫变量):

string s = "欢迎光临!";

Console.WriteLine(s);

Console类是.NET类库的System命名空间下定义的一个类,表示对控制台窗口的抽象。由于程序已引用了该命名空间,因此在 Main 方法的代码中可以直接使用该类。如果删除程序第二行的using引用代码,那么在使用Console类时还需要指定该类所属的命名空间:

System.Console.WriteLine("欢迎光临!");

Console类是控制台应用程序与用户交互的基础,表2-1列出了其常用的一些输入/输出方法。表2-1 Console类的常用成员方法

同理,在其他程序中使用程序P2_1中的Program类也可以采用这两种方式:一是直接使用全称“P2_1.Program”;二是先在其他程序中引用命名空间P2_1,而后使用简称“Program”。不过,如果存在命名冲突(如其他程序中也定义了名为“Program”的类),那么就必须使用全称来加以区分。

程序P2_1虽然简单,但我们从中看到了C#应用程序的基本结构:命名空间下包含类,类可以包含成员字段和成员方法,方法中又包含执行代码。这种包含关系都是通过一对大括号“{}”来表示的。2.2.4 程序主方法

程序的功能是通过执行方法代码来实现的,每个方法都是从其第一行代码开始执行,直至最后一行代码结束,期间可以通过代码来调用其他方法,从而完成各式各样的操作。应用程序的执行必须要有一个起点。C#程序的起点就是由Main定义的,程序总是从Main方法的第一行代码开始执行,在Main方法结束时停止运行。

因此,对于C#可执行程序,其中必须有一个类定义了Main方法,那么编译器就会确定该方法作为程序的入口。如果有多个类都定义了Main方法,那么还需要通过编译选项main明确指定主方法所属的类。例如下面的编译命令就指定Program类中的Main方法作为程序主方法:

csc /main:Program P2_1.cs2.2.5 程序集

人们使用代码编写的是源程序文件,它必须通过编译后才可执行,而编译生成的程序模块叫做程序集(Assembly)。程序集是.NET应用程序的基本单元,一个软件系统可以是一个程序集,但更多时候是多个相互调用的程序集组成的集合。

.NET Framework中提供了C#的编译器和运行环境。因此只要安装了该框架(可从Microsoft网站免费下载),那么开发人员就可以使用各种文本编辑器来编写C#程序代码,而后编译和执行程序。

程序集可以是exe可执行文件格式,也可以是dll动态链接库文件;后者主要是为其他程序提供各种类型和服务,本身并不能直接启动,因此程序中可以不包含 Main 方法。例如,下面的编译命令使用了target选项来将程序P2_1编译为动态链接库文件P2_1.dll:

csc /target:dll P2_1.cs

下面的程序P2_2则调用了程序P2_1中的Program.Main方法:

//程序P2_2

using System;

namespace P2_2

{

public class Program

{

Console.WriteLine("请输入姓名:");

string name = Console.ReadLine();

Console.Write(name);

Console.Write(",");

P2_1.Program.Main();

}

}

那么,在编译程序P2_2时,就需要添加对P2_1.dll(或P2_1.exe)的引用,相应的编译选项为reference(可简写为r):

csc /reference:P2_1.dll P2_2.cs

程序P2_2的运行结果如图2-2所示。图2-2 程序P2_2的输出结果示例2.3 Visual Studio开发环境2.3.1 集成开发环境概述

对于大型软件系统开发,仅仅使用编译器命令是远远不够的。集成开发环境(Integrated Development Environment,IDE)将代码编辑器、编译器、调试器、图形界面设计器等工具和服务集成在一个环境中,能够有效提高软件开发的效率。

Visual Studio.NET 是最流行的.NET 应用程序集成开发环境,开发的每个程序集对应一个Visual Studio项目(Project),而多个相关的项目又可组成一个Visual Studio解决方案(Solution)。

使用Visual Studio标准版、专业版或企业版,可使用Visual C#、Visual Basic .NET、Visual C++ .NET等不同的语言来创建程序项目,并可以将这些项目包含在同一个解决方案中。

启动Visual Studio开发环境,可以看到如图2-3所示的主界面,主要包括以下几部分。

•菜单栏:位于标题栏的下方,其中包含了用于开发、维护、编译、运行和调试程序以及配置开发环境的各项命令。

•工具栏:位于菜单栏的下方,提供了常用命令的快捷操作方式。

•代码编辑区:位于开发环境中央,是编辑代码或设计程序的主区域。

•输出窗口:位于代码编辑区的下方,用于输出当前操作得到的结果。

•解决方案资源管理器:位于开发环境的右侧,它通过树型视图对当前解决方案进行管理,解决方案是树的根节点,解决方案中的每个项目都是根节点的一个子节点,项目节点下则列出了该项目中使用的各种文件、引用和其他资源。

•服务器资源管理器:位于开发环境的左侧,用于快速访问本地或网络上的各项服务器资源。

•属性窗口:位于解决方案资源管理器的下方,用于查看或编辑当前所选元素(如项目、文件、控件等)的具体信息。图2-3 Visual Studio开发环境

•状态栏:位于开发环境的底部,用于对光标位置、编辑方式等当前状态给出提示。

图2-3所示为Visual Studio各窗口的默认位置,而这些窗口还可根据用户需要来移动、调整、打开或关闭,或是通过“视图”菜单来控制它们的显示;其中大部分窗口还可以通过选项卡的方式来进行切换,如代码编辑区可一次打开多个源文件,这就能最大程度地利用有限的屏幕空间。其他常用的窗口还有管理程序中的类及其关系的类视图(可与解决方案资源管理器进行切换显示)、作为控件集合的工具箱(可与服务器资源管理器进行切换显示)等。

Visual Studio 解决方案将被保存为.sln 文件,而单个C#程序项目则会被保存为.csproj 文件。接下来介绍使用Visual Studio创建4种基本的C#应用程序项目的步骤。2.3.2 创建控制台应用程序

如果要在Visual Studio开发环境中创建程序P2_1,那么可通过菜单命令“文件→新建→项目”打开如图2-4所示的对话框,在左侧的项目类型视图中选择“Visual C#”,在右侧的模板视图中选择“控制台应用程序”,输入项目名称,必要时可指定项目存放的位置及所属的解决方案(在对话框左上角的下拉框中还可选择目标程序所依赖的.NET Framework版本),而后按下“确定”按钮。此时Visual Studio就会帮助我们自动完成下列工作。图2-4 “新建项目”对话框(1)将.NET类库中的基本程序集添加到项目引用中。(2)生成 C#源文件 Program.cs(用户可在随后修改其文件名),其中包含对常用命名空间的引用,以及程序命名空间、主程序类和Main方法的基本框架。(3)生成项目配置文件,在其中保存项目的基本信息。

之后开发人员就可以编辑源文件中的程序代码,必要时还可增加新的源文件、程序集引用和其他资源,并通过菜单命令编译和运行程序。此外,使用快捷键 F6 可以直接编译程序,使用快捷键F5可以直接调试运行程序,或是按Ctrl+F5组合键不调试而直接运行程序。2.3.3 创建和使用动态链接库程序

如果要创建动态链接库程序,那么可在图2-4所示的“新建项目”对话框中选择“类库”模板,之后同样可以编写代码来定义各种类型及其成员。不过此类项目只能编译成 dll 动态链接库文件,而不能直接运行。例如,旅行社管理系统中的业务类库就可以创建为一个动态链接库程序项目,其输出可供旅行社内部管理子系统和旅行社网站使用。

在解决方案资源管理器的项目节点下,展开“引用”子节点就可以看到当前项目中包含的对其他程序集(包括动态链接库和可执行文件)的引用,如图2-5所示。如果要添加新的引用,那么可通过菜单命令“项目→添加引用”打开如图2-6所示的对话框,在其中选择指定的程序集并按下“确定”按钮。其中“.NET”选项卡下列出的是.NET 类库中的程序集;在“浏览”选项卡下指定程序集文件的路径名,则可引用自定义的程序集;对于组织在同一个解决方案中项目,相互之间可通过“项目”选项卡来进行引用。在程序的编译和部署过程中,Visual Studio 会自动处理当前程序与其引用程序集之间的关联。图2-5 在解决方案中管理程序集引用图2-6 “添加引用”对话框2.3.4 创建Windows应用程序

如果创建带图形界面的Windows应用程序,那么可在图2-4所示的“新建项目”对话框中选择“Windows 应用程序”模板。这时 Visual Studio 会为项目自动生成两个 C#源程序文件,一是Form1.cs,在解决方案资源管理器中双击该文件即可打开窗体的设计视图(见图 2-7),此时在Visual Studio工具箱中可看到一系列可用的Windows窗体控件,其中“公共控件”选项卡下包含了按钮、文本框、单选框、复选框等常用的Windows控件,通过鼠标拖放就能把这些控件添加到窗体中。

同样,在Visual Studio开发环境中按F5功能键可以调试运行程序,在程序启动时将看到一个和设计视图内容基本一致的Windows窗体。而如果在解决方案资源管理器中选中Form1.cs,单击鼠标右键并选择“查看代码”,就可以查看其源代码,其中有如下的类定义:

public partial class Form1 : Form图2-7 工具箱与窗体设计视图

Form1就是程序定义的Windows窗体类,它继承自从.NET类库中的Form类,而Form类提供了Windows窗体的基本框架以及与用户交互的基本功能。在解决方案资源管理器中选择当前项目,通过菜单命令“项目→添加Windows窗体”还可以向项目中加入新的窗体。

另一个程序文件是Program.cs,它定义了包含Main方法的主程序类Program,其基本代码如下:

//程序P2_3(Program.cs)

using System;

usingSystem.Windows.Forms;

namespace P2_3

{

static class Program

{

static void Main()

{

Application.EnableVisualStyles();

Application.SetCompatibleTextRenderingDefault(false);

Application.Run(new Form1());

}

}

}

代码中的Application类表示当前的Windows应用程序,其Run方法就用于在程序启动时打开主窗体Form1,它和Form类都在System.Windows.Forms命名空间下定义。在Windows应用程序项目中一般不用修改Program.cs中的代码。

Visual Studio中创建的C#Windows应用程序还包含一个隐含源文件Form1. Designer. cs,通过设计视图对窗体进行设置所生成的代码都将保存在该文件中。通常开发人员也无须手动修改该文件中的代码。

例如,在旅行社管理系统中,若是旅行社内部管理子系统只在单位办公计算机上使用,那么可将其创建为一个Windows应用程序项目。2.3.5 创建ASP .NET应用程序

在Visual Studio中还可以方便地创建ASP .NET Web应用程序。在如图2-4所示的“新建项目”对话框中选择“ASP .NET Web应用程序”模板,Visual Studio就会创建一个基本的Web网站框架,其中包括默认主页 Default.aspx、“关于”页面 About.aspx,以及其他相关程序和配置文件。选中当前项目,通过菜单命令“添加→新建项”,在打开的对话框中选择“Web窗体”,就可以向项目中加入新的aspx网页。

如果不希望使用任何自动生成的页面,那么可在“新建项目”对话框中选中左侧“Visual C#”节点下的“Web”节点,再在右侧选择“ASP .NET 空 Web 应用程序”模板,这样就可以从零开始创建一个ASP .NET程序。

在Visual Studio中还可以通过菜单命令“文件→新建→网站”来创建ASP .NET网站,这样创建的程序项目与使用的“ASP .NET Web应用程序”模板得到的结果基本相同。二者的区别在于,前者的项目是配置在当前服务器的文件系统上,编译后就可通过网络进行访问;后者则主要用于本地开发和调试,之后需要部署到服务器上才能进行远程访问。

确切地说,ASP .NET程序项目的每一个网页都包含两个文件:一个设计文件(后缀名为.aspx)和一个C#源代码文件(后缀名为.aspx.cs)。打开aspx设计文件,在Visual Studio工具箱中可看到一系列可用的Web窗体控件,如按钮、文本框、单选框、复选框等,其中许多控件的外观或功能都和Windows控件类似,通过鼠标拖放同样可把这些控件添加到网页中。此外,网页的设计视图左下方还有“设计”、“拆分”、“源”3 个小按钮,单击“设计”按钮可看到图形化的网页界面,单击“源”按钮则切换到网页的HTML视图,单击“拆分”按钮则可以同时显示HTML视图和图形界面,此时对HTML内容的修改可直接反映到界面上,如图2-8所示。图2-8 网页设计视图

运行ASP.NET应用程序,系统会自动启动浏览器,并在其中显示相关的网页内容,如图2-9所示。图2-9 ASP .NET应用程序运行示例2.4 小结

C#是.NET Framework上的核心编程语言,具有语法简洁、类型安全和完全面向对象的特点,能够有效提高软件开发的生产率。

类是C#应用程序的核心要素,类中包含成员字段和成员方法,程序功能主要通过方法代码来实现。C#使用命名空间来对类进行组织和管理。

Visual Studio 是.NET 应用程序的集成开发环境,在其中可以方便地创建和维护 C#控制台应用程序、动态链接库、Windows应用程序、ASP .NET Web应用程序等各种程序项目。2.5 习题

1.C#程序的执行过程是怎样的?哪些方法会在程序中执行?

2.Visual Studio开发环境包含哪些基本菜单?它们主要用于完成哪些工作?

3.在Visual Studio 中创建控制台应用程序和Windows 应用程序时,默认引用了哪些系统程序集文件?

4.简述从C#源代码到可执行程序指令的转换过程。

5.创建一个C#类库动态链接库程序,在其中定义一个方法来计算两个数的和;再创建一个C#控制台应用程序,在其中调用动态链接库程序的求和方法。第3章C#语法基础

在深入探讨C#面向对象程序设计之前,首先需要掌握C#语言的基本语法结构。本章将讲解了C#语言中的数据类型、操作符和表达式、程序控制结构这几项基本要素。3.1 数据类型

数据类型是对客观数据对象的抽象,它将数据和对数据的操作封装为一个整体。C#语言中的数据类型分为两大类:值类型和引用类型。值类型包括整数、字符、实数、布尔数等简单值类型,以及结构(Struct)和枚举(Enum)这两种复合值类型;引用类型则包括类、接口(Interface)、委托(Delegate)和数组。这些类型在本质上都是面向对象的。委托和接口将分别在第6章和第10章中介绍。3.1.1 简单值类型

1.整数类型

整数类型是对数学中的整数的抽象,但由于受到计算机存储限制,程序设计语言中的值类型总是要设置取值范围限制。C#定义了以下8种整数类型。31

•int:32位整数,取值范围为-2147483648(−2)~312147483647(2−1)。

•uint:32位无符号整数(即正整数),取值范围为0~324294967295(2−1)。

•long:64 位长整数,取值范围为63−9223372036854775808(−2)~63922372036854775807(2−1)。

•ulong:64位无符号整数,取值范围为0~6418446744073709551615(2−1)。15

•short:16位短整数,取值范围为−32768(−2)~1532767(2-1)。16

•ushort:16位无符号短整数,取值范围为0~65535(2−1)。7

•sbyte:8位字节型整数,取值范围为−128(−2)~7127(2−1)。8

•byte:8位无符号字节型整数,取值范围为0~255(2−1)。

例如,下面的代码就先定义了一个整型变量x,而后将其赋值为80:

int x;

x = 80;

上述两行代码还可以合并为:

int x = 80;

如果是同类型的多个变量,那么C#允许将它们的声明语句简写到一行代码中,例如:

int x1 = 10, x2, x3 = 20; //x2还未被赋值

而下面这些语句则是错误的:

uint x = -10; //错误:无符号整数不能取负数

byte y = 500; //错误:超出了取值范围

longz;

Console.WriteLine(z); //错误:z在被赋值前不能使用

定义变量时应尽量选择最为适合的类型:过短的类型可能不足以表达变量的变化范围,过长的类型则会造成资源浪费。例如要表示人的年龄 byte 类型就足够了,要表示人口的数量则 uint类型会比较适合。

2.字符类型

C#中使用char来表示字符类型。由于使用了16位Unicode 字符集,char类型不仅包含基本的ASCII字符,还能够表示汉字等各国语言符号。注意单个字符值要用一对单引号括起来;如果使用了双引号,那么它表示的就是只有一个字符的字符串。例如:

char a = 's';

char b = '人';

string s = "人";

对于像单引号、回车符这样的特殊字符,C#中使用加斜杠“\”的转义符来表示。例如:

char a1 = '\''; //a1表示单引号

char a2 = '\\'; //a2表示单斜杠

char a3 = '\r'; //a3表示回车符

表3-1列出了C#中常见的一些转义符格式。表3-1 C#常用转义符

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载