C#图解教程(第4版)(txt+pdf+epub+mobi电子书下载)


发布时间:2020-06-04 19:26:05

点击下载

作者:(美)Daniel M. Solis 著

出版社:人民邮电出版社

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

C#图解教程(第4版)

C#图解教程(第4版)试读:

前言

本书的目的是讲授C#编程语言的基础知识和工作原理。C#是一门非常棒的编程语言,我喜欢用它编写代码!这些年来,我自己都不记得学过多少门编程语言了,但C#一直是我的最爱。我希望购买本书的读者能从书中读到C#的美和优雅。

大多数编程图书以文字为主要载体。对于小说而言,文字形式当然是最恰当不过了,但对于编程语言中的很多重要概念,综合运用文字、图形和表格会更容易理解。

许多人都习惯于形象思维,而图形和表格有助于我们更清晰地理解概念。在几年的编程语言教学工作中我发现,我在白板上画的图能帮助学生最快地理解我要传达的概念。然而,单靠图表并不足以解释一种编程语言和平台。本书的目标是以最佳方式结合文字和图表,使你对这种语言有透彻的理解,并且让本书能用作参考工具。

本书写给所有想要学习C#的人——从初学者到有经验的程序员。刚开始学编程的人会发现,书中全面讲述了基础知识;有经验的程序员会觉得,内容的叙述非常简洁明晰,无需费力卒读就能直接获得想要的信息。无论哪种程序员,内容本身的图形化呈现方式都能帮助你更容易地学习本书。

祝学习愉快!目标读者、源代码和联系信息

本书针对编程新手和中级水平的程序员,当然还有对C#感兴趣的其他语言编程人员(如Visual Basic和Java)。我尽力专注C#语言本身,详尽深入地描述语言及各部分,少涉及.NET和相关编程实践。本书写作过程中,笔者始终坚持确保内容简洁性的同时又能透彻地讲解这门语言。如果读者对其他主题感兴趣,有大量好书值得推荐。

你可以从Apress网站本书页面(www.illustratedcsharp.com)下载书中所有示例程序的源代码。尽管我不能回答有关代码的一些细节问题,但是你可以通过dansolis@sbcglobal.net和我取得联系,提出建议或反馈。

我希望本书可以让你享受学习C#的过程!祝你好运!致谢

感谢Sian每天支持并鼓励我,感谢我的父母、兄弟和姐妹,他们一直爱我并支持我。

我还想对Apress的朋友表达诚挚的感谢,是他们与我携手完成了本书。我真心感激他们理解并赏识我努力做的事情,并和我一起完成它。感谢你们所有人!第1章C#和.NET框架本章内容● 在.NET之前● .NET时代● 编译成CIL● 编译成本机代码并执行● CLR● CLI● 缩写回顾● C#的演化1.1 在.NET之前1

C#编程语言是为在微软公司的.NET框架上开发程序而设计的。本章将简要介绍.NET从何而来,以及它的基本架构。在开始之前,2我要指出C#的正确发音:see sharp。微软正式中文文献中一般称.NET Framework,本书考虑了国内1读者习惯,统一译为.NET框架。——编者注

有一次我去应聘一个C#编程的职位,当时人力资源面试官问我2从事“see pound”(应为see sharp)的经验有多少!我过了一会儿才弄清楚他在说什么。1.1.1 20世纪90年代末的Windows编程

20世纪90年代末,使用微软平台的Windows编程分化成许多分支。大多数程序员使用Visual Basic(VB)、C或C++。一些C和C++程序员在使用纯Win32 API,但大多数人在使用MFC(Microsoft Foundation Class,微软基础类库)。其他人已经转向了COM(Component Object Model,组件对象模型)。

所有这些技术都有自己的问题。纯Win32 API不是面向对象的,而且使用它的工作量比使用MFC的更大。MFC是面向对象的,但是它却不一致,并逐渐变得陈旧。COM虽然概念简单,但它的实际代码复杂,并且需要很多丑陋的、不雅的底层基础代码。

所有这些编程技术还有一个缺点是它们主要针对桌面程序而不是Internet进行开发。那时,Web编程还是以后的事情,而且看起来和桌面编程非常不同。1.1.2 下一代平台服务的目标

我们真正需要的是一个新的开始——一个集成的、面向对象的开发框架,它可以把一致和优雅带回编程。为满足这个需求,微软打算开发一个代码执行环境和一个可以实现这些目标的代码开发环境。这些目标列在图1-1中。图1-1 下一代平台的目标1.2 .NET时代

2002年,微软发布了.NET框架的第一个版本,声称其解决了旧问题并实现了下一代系统的目标。.NET框架是一种比MFC和COM编程技术更一致并面向对象的环境。它的特点包括以下几点。● 多平台 该系统可以在各种计算机上运行,从服务器、桌面机到

PDA,还能在移动电话上运行。● 行业标准 该系统使用行业标准的通信协议,比如XML、

HTTP、SOAP、JSON和WSDL。● 安全性 该系统能提供更加安全的执行环境,即使有来源可疑的

代码存在。1.2.1 .NET框架的组成3

.NET框架由三部分组成,如图1-2所示。 执行环境称为CLR(Common Language Runtime,公共语言运行库)。CLR在运行时管理程序的执行,包括以下内容。

严格地说,.NET框架由CLR和FCL(框架类库)两部分组成,不3包括工具。FCL是BCL的超集,还包括Windows Forms、ASP.NET、LINQ以及更多命名空间。——编者注● 内存管理和垃圾收集。● 代码安全验证。● 代码执行、线程管理及异常处理。图1-2 .NET框架的组成

编程工具涵盖了编码和调试需要的一切,包括以下几点。● Visual Studio集成开发环境(IDE)。● .NET兼容的编译器(例如:C#、Visual Basic .NET、F#、

IronRuby和托管的C++)。● 调试器。● 网站开发服务器端技术,比如ASP.NET或WCF。

BCL(Base Class Library,基类库)是.NET框架使用的一个大的类库,而且也可以在你的程序中使用。1.2.2 大大改进的编程环境

较之以前的Windows编程环境,.NET框架为程序员带来了相当大的改进。下面几节将简要阐述它的特点及其带来的好处。1. 面向对象的开发环境CLR、BCL和C#完全是面向对象的,并形成了良好的集成环

境。系统为本地程序和分布式系统都提供了一致的、面向对象的

编程模型。它还为桌面应用程序、移动应用程序和Web开发提供

了软件开发接口,涉及的目标范围很广,从桌面服务器到手机。2. 自动垃圾收集CLR有一项服务称为GC(Garbage Collector,垃圾收集器),

它能为你自动管理内存。● GC自动从内存中删除程序不再访问的对象。GC使程序员不再操心许多以前必须执行的任务,比如释放

内存和检查内存泄漏。这可是个很大的改进,因为检查内存泄漏

可能非常困难而且耗时。3. 互操作性.NET框架专门考虑了不同的.NET语言、操作系统或Win32

DLL和COM之间的互操作性。● .NET语言的互操作性允许用不同的.NET语言编写的软件模块无缝地交互。■ 一种.NET语言写的程序可以使用甚至继承用另外一种.NET语言写的类,只需要遵循一定的规则即可。■ 正因为能够很容易地集成不同编程语言生成的模块,.NET框架有时被称为是语言无关的。● .NET提供一种称为平台调用(platform invoke, P/Invoke)的特性,允许.NET的代码调用并使用非.NET的代码。它可以使用标准Win32 DLL导出的纯C函数的代码,比如Windows API。● .NET框架还允许与COM进行互操作。.NET框架软件组件能调用COM组件,而且COM组件也能调用.NET组件,就像它们是COM组件一样。4. 不需要COM.NET框架使程序员摆脱了COM的束缚。作为一个C#程序员,

你肯定很高兴不需要使用COM编程环境,因而也不需要下面这

些内容。● IUnknown接口 在COM中,所有对象必须实现IUnknown接口。相反,所有.NET对象都继承一个名为object的类。接口编程仍是.NET中的一个重要部分,但不再是中心主题了。● 类型库 在COM中,类型信息作为.tlb文件保存在类型库中,它和可执行代码是分开的。在.NET中,程序的类型信息和代码一起被保存在程序文件中。● 手动引用计数 在COM中,程序员必须记录一个对象的引用数目以确保它不会在错误的时间被删除。在.NET中,GC记录引用情况并只在合适的时候删除对象。● HRESULT COM使用HRESULT数据类型返回运行时错误代码。.NET不使用HRESULT。相反,所有意外的运行时错误都产生异常。● 注册表 COM应用必须在系统注册表中注册。注册表保存了与操作系统的配置和应用程序有关的信息。.NET应用不需要使用注册表,这简化了程序的安装和卸载。(但有功能类似的工具,称为全局程序集缓存,即GAC,我会在第21章阐述。)尽管现在不太需要编写COM代码了,但是系统中还是在使

用很多COM组件,C#程序员有的时候需要编写代码来和那些组

件交互。C# 4.0引入了几个新的特性,来简化这个工作,我们将

在第25章讨论。5. 简化的部署为.NET框架编写的程序进行部署比以前容易很多,原因如

下。● .NET程序不需要使用注册表注册,这意味着在最简单的情形下,一个程序只需要被复制到目标机器上便可以运行。● .NET提供一种称为并行执行的特性,允许一个DLL的不同版本在同一台机器上存在。这意味着每个可执行程序都可以访问程序生成时使用的那个版本的DLL。6. 类型安全性CLR检查并确保参数及其他数据对象的类型安全,不同编程

语言编写的组件之间也没有问题。7. 基类库.NET框架提供了一个庞大的基础类库,很自然地,它被称

为基类库(Base Class Library, BCL)。(有时称为框架类库——4

Framework Class Library,FCL。)在写自己的程序时,可以使

用其中的类,如下所示。● 通用基础类 这些类提供了一组极为强大的工具,可以应用到许多编程任务中,比如文件操作、字符串操作、安全和加密。● 集合类 这些类实现了列表、字典、散列表以及位数组。● 线程和同步类 这些类用于创建多线程程序。● XML类 这些类用于创建、读取以及操作XML文档。

严格地说,BCL并不等同于FCL,而只是FCL的一个子集,包括4System、System.IO、System.Resources、System.Text等FCL中比较底层和通用的功能。——编者注1.3 编译成CIL

.NET语言的编译器接受源代码文件,并生成名为程序集的输出文件。图1-3阐述了这个 过程。● 程序集要么是可执行的,要么是DLL。● 程序集里的代码并不是本机代码,而是一种名称为

CIL(Common Intermediate Language,公共中间语言)的中间

语言。● 程序集包含的信息中,包括下列项目:● 程序的CIL;● 程序中使用的类型的元数据;● 对其他程序集引用的元数据。图1-3 编译过程说明 随着时间的推移,公共中间语言的缩写已经改变,而且不同的参考书可能使用不同的术语。大家经常遇到的与CIL有关的另外两个术语是IL(Intermediate Language)和MSIL(Microsoft Intermediate Language),它们在.NET发展初期和早期文档中频繁使用,不过现在已经用得很少了。1.4 编译成本机代码并执行

程序的CIL直到它被调用运行时才会被编译成本机代码。在运行时,CLR执行下面的步骤(如图1-4所示):● 检查程序集的安全特性;● 在内存中分配空间;● 把程序集中的可执行代码发送给实时(Just-in-Time, JIT)编译

器,把其中的一部分编译成本机代码。图1-4 运行时被编译成本机代码

程序集中的可执行代码只在需要的时候由JIT编译器编译,然后它就被缓存起来以备在后来的程序中执行。使用这个方法意味着不被调用的代码不会被编译成本机代码,而且被调用到的代码只被编译一次。

一旦CIL被编译成本机代码,CLR就在它运行时管理它,执行像释放无主内存、检查数组边界、检查参数类型和管理异常之类的任务。有两个重要的术语由此而生。● 托管代码 为.NET框架编写的代码称为托管代码(managed

code),需要CLR。● 非托管代码 不在CLR控制之下运行的代码,比如Win32 C/C++

DLL,称为非托管代码(unmanaged code)。

微软公司还提供了一个称为本机映像生成器的工具Ngen,可以把一个程序集转换成当前处理器的本机代码。经过Ngen处理过的代码免除了运行时的JIT编译过程。编译和执行

无论原始源文件的语言是什么,都遵循同样的编译和执行过程。图1-5说明了3个用不同语言编写的程序的完整编译时和运行时过程。图1-5 编译时和运行时过程概览1.5 CLR

.NET框架的核心组件是CLR,它在操作系统的顶层,负责管理程序的执行,如图1-6所示。

CLR还提供下列服务:● 自动垃圾收集;● 安全和认证;● 通过访问BCL得到广泛的编程功能,包括如Web服务和数据服务

之类的功能。图1-6 CLR概览1.6 CLI

每种编程语言都有一组内置的类型,用来表示如整数、浮点数和字符等之类的对象。过去,这些类型的特征因编程语言和平台的不同而不同。例如,组成整数的位数对于不同的语言和平台就有很大差别。

然而,这种统一性的缺乏使我们难以让使用不同语言编写的程序及库一起良好协作。为了有序协作,必须有一组标准。

CLI(Common Language Infrastructure,公共语言基础结构)就是这样一组标准,它把所有.NET框架的组件连结成一个内聚的、一致的系统。它展示了系统的概念和架构,并详细说明了所有软件都必须坚持的规则和约定。CLI的组成如图1-7所示。图1-7 CLI的组成

CLI和C#都已经被Ecma International批准为开放的国际标准规范。[Ecma本来是Europen Computer Manufacturer Association(欧洲计算机制造商协会)的缩写,但现在已经不是缩写了,它就是一个词。]Ecma的成员包括微软、IBM、惠普、Adobe等众多和计算机及消费性电子产品有关的公司。CLI的重要组成部分

虽然大多数程序员不需要了解CLI规范的细节,但至少应该熟悉公共类型系统和公共语言规范的含义和用途。1. 公共类型系统CTS(Common Type System,公共类型系统)定义了那些

在托管代码中一定会使用的类型的特征。CTS的一些重要方面如

下。● CTS定义了一组丰富的内置类型,以及每种类型固有的、独有的特性。● .NET兼容编程语言提供的类型通常映射到CTS中已定义的内置类型集的某一个特殊子集。● CTS最重要的特征之一是所有类型都继承自公共的基类——object。● 使用CTS可以确保系统类型和用户定义类型能够被任何.NET兼容的语言所使用。2. 公共语言规范CLS(Common Language Specification,公共语言规范)详

细说明了一个.NET兼容编程语言的规则、属性和行为,其主题

包括数据类型、类结构和参数传递。1.7 各种缩写

本章包含了许多.NET缩写,图1-8将帮助你直观地理解它们。图1-8 .NET缩写1.8 C#的演化

C#的最新版本是5.0。每个新版本在新添加的特性中都有一个焦点特性。5.0的焦点特性是异步编程,将在第20章展开介绍。

图1-9阐明了C#每个版本的焦点特性以及本书哪些章节会讨论它们。图1-9 C#各版本的焦点特性第2章C#编程概述本章内容● 一个简单的C#程序● 标识符● 关键字● Main:程序的起始点● 空白● 语句● 从程序中输出文本● 注释:代码的注解2.1 一个简单的C#程序

本章将为学习C#打基础。因为本书中会广泛地使用代码示例,所以我们先来看看C#程序的样子,还有它的不同部分代表什么意思。

我们从一个简单程序开始,逐个解释它的各组成部分。这里将会介绍一系列主题,从C#程序的结构到产生屏幕输出程序的方法。

有这些源代码作为初步铺垫,我就可以在余下的文字中自由地使用代码示例了。因此,与后面的章节详细阐述一两个主题不同,本章将接触很多主题并只给出最简单的解释。

让我们先观察一个简单的C#程序。完整的源程序在图2-1上面的阴影区域中。如图所示,代码包含在一个名称为SimpleProgram.cs的文本文件里。当你阅读它时,不要担心能否理解所有的细节。表2-1对代码进行了逐行描述。图中左下角的阴影区域展示了程序的输出结果,右半边是程序各部分的图形化描述。● 当代码被编译执行时,它在屏幕的一个窗口中显示字符串“Hi

there!”。● 第5行包含两个相邻的斜杠。这两个字符以及这一行中它们之后

的所有内容都会被编译器忽略。这叫做单行注释。图2-1 SimpleProgram程序表2-1 SimpleProgram程序的逐行描述行号描述行1告诉编译器这个程序使用System命名空间的类型声明一个新命名空间,名称为Simple• 新命名空间从第4行的左大括号开始一直延伸到行3第12行与之对应的右大括号• 在这部分里声明的任何类型都是该命名空间的成员声明一个新的类类型,名称为Program行5• 任何在第6行和第11行的两个大括号中间声明的成员都是组成这个类的成员声明一个名称为Main的方法作为类Program的成员行7• 在这个程序中,Main是Program类的唯一成员• Main是一个特殊函数,编译器用它作为程序的起始点只包含一条单独的、简单的语句,这一行组成了Main的方法体• 简单语句以一个分号结束行9• 这条语句使用命名空间System中的一个名称为Console的类将消息输出到屏幕窗口• 没有第1行的using语句,编译器就不会知道在哪里寻找类ConsoleSimpleProgram的补充说明

C#程序由一个或多个类型声明组成。本书的大部分内容都是用来解释可以在程序中创建和使用的不同类型。程序中的类型可以以任何顺序声明。在SimpleProgram中,只声明了class类型。

命名空间是与某个名称相关联的一组类型声明。SimpleProgram使用两个命名空间。它创建了一个名称为Simple的新命名空间,并在其中声明了其类型(类program),还使用了System命名空间中定义的Console类。

要编译这个程序,可以使用Visual Studio或命令行编译器。如果使用命令行编译器,最简单的形式是在命名窗口使用下面的命令:csc SimpleProgram.cs

在这条命令中,csc是命令行编译器的名称,SimpleProgram.cs是源文件的名称。CSC是指“C-Sharp编译器”。2.2 标识符

标识符是一种字符串,用来命名如变量、方法、参数和许多后面将要阐述的其他程序结构。

可以通过把有意义的词连接成一个单独的描述性名称来创建自文档化(self-documenting)的标识符,可以使用大写和小写字母(如CardDeck、PlayersHand、FirstName和SocialSecurityNum)。某些字符能否在标识符中特定的位置出现是有规定的,这些规则如图2-2所示。● 字母和下划线(a-z、A-Z和_)可以用在任何位置。● 数字不能放在首位,但可以放在其他的任何地方。● @字符只能放在标识符的首位。虽然允许使用,但不推荐将@作

为常用字符。图2-2 标识符中允许使用的字符

标识符区分大小写。例如,变量名myVar和MyVar是不同的标识符。

举个例子,在下面的代码片段中,变量的声明都是有效的,并声明了不同的整型变量。但使用如此相似的名称会使代码更易出错并更难调试,后续需要调试代码的人会很不爽。// 语法上有效,但非常混乱int totalCycleCount;int TotalCycleCount;int TotalcycleCount;

我将在第7章介绍推荐的C#命名约定。2.3 关键字

关键字是用来定义C#语言的字符串记号。表2-2列出了完整的C#关键字表。

关于关键字,一些应该知道的重要内容如下。● 关键字不能被用做变量名或任何其他形式的标识符,除非以@字

符开始。● 所有C#关键字全部都由小写字母组成(但是.NET类型名使用

Pascal大小写约定)。表2-2 C#关键字typeofabstractconstexternintoutshortinterfacascontinuefalseoverridesizeofuinteparamsfinallyulongbasedecimalinternalstackallocuncheckprivatebooldefaultfixedisstaticeddelegatprotectestringbreakfloatlockunsafeedBytelongpublicdoforstructushortnamespreadonlcaseusingdoubleforeachswitchaceygotonewcatchelserefthisvirtualenumcharifnullreturnthrowvoidimplicitobjectsbytecheckedeventtruevolatileexplicitoperatortryclassinsealedwhile

上下文关键字是仅在特定的语言结构中充当关键字的标识符。在那些位置,它们有特别的含意。两者的区别是,关键字不能被用做标识符,而上下文关键字可以在代码的其他部分被用做标识符。上下文关键字如表2-3所示。表2-3 C#的上下文关键字ascendinasyncbydescendingdynamicaddawaitgequalgroupgetglobalfrominintosjoinonorderbypartialremoveletselectvaryieldsetvaluewhere2.4 Main:程序的起始点

每个C#程序必须有一个类带有Main方法(函数)。在先前所示的SimpleProgram程序中,它被声明在Program类中。● 每个C#程序的可执行起始点在Main中的第一条指令。● Main必须首字母大写。

Main的最简单形式如下:static void Main( ){ 更多语句}2.5 空白

程序中的空白指的是没有可视化输出的字符。程序员在源代码中使用的空白将被编译器忽略,但使代码更清晰易读。空白字符包括:● 空格(Space);● 制表符(Tab);● 换行符;● 回车符。

例如,下面的代码段会被编译器完全相同地对待而不管它们表面上的区别。// 很好的格式Main(){ Console.WriteLine("Hi, there!");}// 连在一起Main(){Console.WriteLine("Hi, there!");}2.6 语句

C#的语句和C、C++的语句非常相似。本节将介绍语句的常用形式,详细的语句形式将在第9章介绍。

语句是描述一个类型或告诉程序去执行某个动作的一条源代码指令。● 简单语句以一个分号结束。

例如,下面的代码是一个由两条简单语句组成的序列。第一条语句定义了一个名称为var1的整型变量,并初始化它的值为5。第二条语句将变量var1的值打印到屏幕窗口。int var1 = 5;System.Console.WriteLine("The value of var1 is {0}", var1);块

块是一个由成对大括号包围的0条或多条语句序列,它在语法上相当于一条语句。

可以使用之前示例中的两条语句创建一个块。用大括号把语句包围起来,如下面的代码所示。{ int var1 = 5; System.Console.WriteLine("The value of var1 is {0}", var1);}

关于块,一些应该知道的重要内容如下。● 语法上只需要一条语句,而你需要执行的动作无法用一条简单的

语句表达的情况下,考虑使用块。● 有些特定的程序结构只能使用块。在这些结构中,不能用简单语

句替代块。● 虽然简单语句以分号结束,但块后面不跟分号。(实际上,

由于被解析为一条空语句,所以编译器允许这样,但这不是好的

风格。)

{ 以分号结束

↓ 以分号结束

int var1 = 5; ↓

System.Console.WriteLine("The value of var1 is {0}", var1);

}

↑ 不以分号结束2.7 从程序中输出文本

控制台窗口是一种简单的命令提示窗口,允许程序显示文本并从键盘接受输入。BCL提供一个名称为Console的类(在System命名空间中),该类包含了输入和输出数据到控制台窗口的方法。2.7.1 Write

Write是Console类的成员,它把一个文本字符串发送到程序的控制台窗口。最简单的情况下,Write将文本的字符串字面量发送到窗口,字符串必须使用双引号括起来。

下面这行代码展示了一个使用Write成员的示例:Console.Write("This is trivial text."); ↑ 输出字符串

这段代码在控制台窗口产生如下输出:This is trivial text.

另外一个示例是下面的代码,发送了3个文本字符串到程序的控制台窗口:System.Console.Write ("This is text1. ");System.Console.Write ("This is text2. ");System.Console.Write ("This is text3. ");

这段代码产生的输出如下,注意,Write没有在字符串后面添加换行符,所以三条语句都输出到同一行。This is text1. This is text2. This is text3.------↑------- ------↑------- ------↑------- 第一条 第二条 第三条 语句 语句 语句2.7.2 WriteLine

WriteLine是Console的另外一个成员,它和Write实现相同的功能,但会在每个输出字符串的结尾添加一个换行符。

例如,如果使用先前的代码,用WriteLine替换掉Write,输出就会分隔在多行:System.Console.WriteLine("This is text1.");System.Console.WriteLine("This is text2.");System.Console.WriteLine("This is text3.");

这段代码在控制台窗口产生如下输出:This is text1.This is text2.This is text3.2.7.3 格式字符串

Write语句和WriteLine语句的常规形式中可以有一个以上的参数。● 如果不只一个参数,参数间用逗号分隔。● 第一个参数必须总是字符串,称为格式字符串。格式字符串可以

包含替代标记。● 替代标记在格式字符串中标出位置,在输出串中该位置将用一个值来替代。● 替代标记由一个整数及括住它的一对大括号组成,其中整数就是替换值的数字位置。跟着格式字符串的参数称为替换值,这些替换值从0开始编号。

语法如下:Console.WriteLine(格式字符串(含替代标记),替换值0,替换值1,替换值2,……);

例如,下面的语句有两个替代标记,编号0和1;以及两个替换值,它们的值分别是3和6。 替代标记 ↓ ↓Console.WriteLine("Two sample integers are {0} and {1}.", 3, 6); -------↑------------------- ---↑-- 格式字符串 替换值

这段代码在屏幕上产生如下输出:Two sample integers are 3 and 6.2.7.4 多重标记和值

在C#中,可以使用任意数量的替代标记和任意数量的值。● 值可以以任何顺序使用。● 值可以在格式字符串中替换任意次。

例如,下面的语句使用了3个标记但只有两个值。请注意,值1被用在了值0之前,而且值1被使用了两次。Console.WriteLine("Three integers are {1}, {0} and {1}.", 3, 6);

这段代码在屏幕上显示如下:Three integers are 6, 3 and 6.

标记不能试图引用超出替换值列表长度以外位置的值。如果引用了,不会产生编译错误,但会产生运行时错误(称为异常)。

例如,在下面的语句中有两个替换值,在位置0和1。而第二个标记引用了位置2,位置2并不存在。这将会产生一个运行时错误。 位置0 位置1 ↓ ↓Console.WriteLine("Two integers are {0} and {2}.", 3 6); //错误 ↑ 位置2的值不存在2.7.5 格式化数字字符串

贯穿本书的示例代码将会使用WriteLine方法来显示值。每次,我们都使用由大括号包围整数组成的简单替代标记形式。

然而在很多时候,我们更希望以更合适的格式而不是一个简单的数字来呈现文本字符串的输出。例如,把值作为货币或者某个小数位数的定点值来显示。这些都可以通过格式化字符串来实现。

例如,下面的代码由两条打印值500的语句组成。第一行没有使用任何其他格式化来打印数字,而第二行的格式化字符串指定了数字应该被格式化成货币。Console.WriteLine("The value: {0}." , 500); // 输出数字Console.WriteLine("The value: {0:C}.", 500); // 格式为货币 ↑ 格式化为货币

这段代码产生了如下的输出:The value: 500.The value: $500.00.

两条语句的不同之处在于,格式项以格式说明符形式包括了额外的信息。大括号内的格式说明符的语法由3个字段组成:索引号、对齐说明符和格式字段(format field)。语法如图2-3所示。图2-3 格式说明符的语法

格式说明符的第一项是索引号。如你所知,索引指定了之后的格式化字符串应该格式化列表中的哪一项。索引号是必需的,并且列表项的数字必须从0开始。1. 对齐说明符对齐说明符表示了字段中字符的最小宽度。对齐说明符有如

下特性。● 对齐说明符是可选的,并且使用逗号来和索引号分离。● 它由一个正整数或负整数组成。■ 整数表示了字段使用字符的最少数量。■ 符号表示了右对齐或左对齐。正数表示右对齐,负数表示左对齐。

索引——使用列表中的第0项

Console.WriteLine("{0, 10}", 500);

对齐说明符——在10个字符的字段中右对齐例如,如下格式化int型变量myInt的值的代码显示了两个格

式项。在第一个示例中,myInt的值以在10个字符的字符串中右

对齐的形式进行显示;第二个示例中则是左对齐。格式项放在两

个竖杠中间,这样在输出中就能看到它们的左右边界。

int myInt = 500;

Console.WriteLine("|{0, 10}|", myInt); // 右对齐

Console.WriteLine("|{0,-10}|", myInt); // 左对齐这段代码产生了如下的输出,在两个竖杠的中间有10个字

符:| 500||500 |值的实际表示可能会比对齐说明符指定的字符数多一些或少

一些:● 如果要表示的字符数比对齐说明符中指定的字符数少,那么其余字符会使用空格填充;● 如果要表示的字符数多于指定的字符数,对齐说明符会被忽略,并且使用所需的字符进行表示。2. 格式字段格式字段指定了数字应该以哪种形式表示。例如,应该被当

做货币、十进制数字、十六进制数字还是定点符号来表示?格式字段有三部分,如图2-4所示。● 冒号后必须紧跟着格式说明符,中间不能有空格。● 格式说明符是一个字母字符,是9个内置字符格式之一。字符可以是大写或小写形式。大小写对于某些说明符来说比较重要,而对于另外一些说明符来说则不重要。● 精度说明符是可选的,由1~2位数字组成。它的实际意义取决于格式说明符。图2-4 标准的格式字段字符串如下代码是格式字符串组件语法的一个示例:

索引——使用列表中的第0项

Console.WriteLine("{0:F4}", 12.345678);

格式组件——4位小数的定点数如下代码给出了不同格式字符串的一些示例:

double myDouble = 12.345678;

Console.WriteLine("{0,-10:G} -- General", myDouble);

Console.WriteLine("{0,-10} -- Default, same as General", myDouble);

Console.WriteLine("{0,-10:F4} -- Fixed Point, 4 dec places", myDouble);

Console.WriteLine("{0,-10:C} -- Currency", myDouble);

Console.WriteLine("{0,-10:E3} -- Sci. Notation, 3 dec places", myDouble);

Console.WriteLine("{0,-10:x} -- Hexadecimal integer", 1194719 );这段代码产生了如下的输出:12.345678 -- General12.345678 -- Default, same as General12.3457 -- Fixed Point, 4 dec places$12.35 -- Currency1.235E+001 -- Sci. Notation, 3 dec places123adf -- Hexadecimal integer3. 标准数字格式说明符表2-4总结了9种标准数字格式说明符。第一列在说明符名后

列出了说明符字符。如果说明符字符根据它们的大小写会有不同

的输出,就会标注为区分大小写。表2-4 标准数字格式说明符名字和字意义符使用货币符号把值格式化为货币,货币符号取决于程序所在PC的区域设置货币精度说明符:小数位数C、c示例:Console.WriteLine("{0:C}",12.5);输出:$12.50十进制数字字符串,需要的情况下有负数符号。只能和整数类型配合使用精度说明符:输出字符串中的最少位数。如十进制数果实际数字的位数更少,则在左边以0填充D、d示例:Console.WriteLine("{0:D4}",12);输出:0012带有小数点的十进制数字字符串。如果需要也可以有负数符号精度说明符:小数的位数定点示例:Console.WriteLine("{0:F4}",12.F、f3456789);输出:12.3457在没有指定说明符的情况下,会根据值转换为定点或科学记数法表示的紧凑形式常规精度说明符:根据值G、g示例:Console.WriteLine("{0,G4}",12.345678);输出:12.35十六进制数字的字符串。十六进制数字A~F十六进制会匹配说明符的大小写形式数精度说明符:输出字符串中的最少位数。如X、x果实际数的位数更少,则在左边以0填充区分大小示例:Console.WriteLine("{0:x}",180026);写输出:2bf3a和定点表示法相似,但是在每三个数字的一组中间有逗号或空格分隔符。从小数点开始往左数。使用逗号还是空格分隔符取决于程序所在PC的区域设置数字精度说明符:小数的位数N、n示例:Console.WriteLine("{0:N2}",12345678.54321);输出:12,345,678.54表示百分比的字符串。数字会乘以100百分比精度说明符:小数的位数P、p示例:Console.WriteLine("{0:P2}",0.1221897);输出:12.22%保证输出字符串后如果使用Parse方法将字符串转化成数字,那么该值和原始值一样。Parse方法将在第25章描述往返过程精度说明符:忽略R、r示例:Console.WriteLine("{0:R}",1234.21897);输出:1234.21897具有尾数和指数的科学记数法。指数前面加科学记数字母E。E的大小写和说明符一致法精度说明符:小数的位数E、e示例:Console.WriteLine("{0:e4}",12.区分大小3456789);写输出:1.2346e+0012.8 注释:为代码添加注解

你已经见过单行注释了,所以这里将讨论第二种行内注释——带分隔符的注释,并提及第三种类型,称为文档注释。● 带分隔符的注释有两个字符的开始标记(/*)和两个字符的结束

标记(*/)。● 标记对之间的文本会被编译器忽略。● 带分隔符的注释可以跨任意多行。

例如,下面的代码展示了一个跨多行的带分隔符的注释。 ↓ 跨多行注释的开始/* 这段文本将被编译器忽略 带分隔符的注释与单行注释不同 带分隔符的注释可以跨越多行*/ ↑注释结束

带分隔符的注释还可以只包括行的一部分。例如,下面的语句展示了行中间注释出的文本。该结果就是只声明了一个变量var2。 注释开始 ↓int /*var 1,*/ var2; ↑ 注释结束说明 C#中的单行注释和带分隔符的注释与C和C++中的相同。2.8.1 关于注释的补充

关于注释,有其他几点重要内容需要知道。● 嵌套带分隔符的注释是不允许的,一次只能有一个注释起作用。

如果你打算嵌入注释,首先开始的注释直到它的范围结束都有

效。● 注释类型的范围如下。● 对于单行注释,一直到行结束都有效。● 对于带分隔符的注释,直至遇到第一个结束分隔符都有效。

下面的注释方式是不正确的: ↓创建注释/*尝试嵌套注释 /* ← 它将被忽略,因为它在一个注释的内部 内部注释 */ ← 注释结束,因为它是遇到的第一个结束分隔符*/ ← 产生语法错误,因为没有开始分隔符↓创建注释 ↓它将被忽略,因为它在一个注释的内部//单行注释 /*嵌套注释? */ ←产生语法错误,因为没有开始分隔符2.8.2 文档注释

C#还提供第三种注释类型:文档注释。文档注释包含XML文本,可以用于产生程序文档。这种类型的注释看起来像单行注释,但它们有三个斜杠而不是两个。文档注释会在第25章阐述。

下面的代码展示了文档注释的形式:///

/// This class does.../// class Program{ ...2.8.3 注释类型总结

行内注释是被编译器忽略但被包含在代码中以说明代码的文本片段。程序员在他们的代码中插入注释以解释和文档化代码。表2-5总结了注释的类型。表2-5 注释类型类型开结描述始束 单行注释//从开始标记到该行行尾的文本被编译器忽略带分隔符从开始标记到结束标记之间的文本被编译器忽/**/的注释略这种类型的注释包含XML文本,可以使用工具 文档注释///生成程序文档。详细内容参见第25章第3章类型、存储和变量本章内容● C#程序是一组类型声明● 类型是一种模板● 实例化类型● 数据成员和函数成员● 预定义类型● 用户定义类型● 栈和堆● 值类型和引用类型● 变量● 静态类型和dynamic关键字● 可空类型3.1 C#程序是一组类型声明

如果广泛地描述C和C++程序源代码的特征,可以说C程序是一组函数和数据类型,C++程序是一组函数和类,然而C#程序是一组类型声明。● C#程序或DLL的源代码是一组一种或多种类型声明。● 对于可执行程序,类型声明中必须有一个包含Main方法的类。● 命名空间是一种把相关的类型声明分组并命名的方法。既然程序

是一组相关的类型声明,那么通常会把程序声明在你创建的命名

空间内部。

例如,下面是一个由3个类型声明组成的程序。这3个类型被声明在一个名称为MyProgram的新命名空间内部。namespace MyProgram //创建新的命名空间{ DeclarationOfTypeA //声明类型 DeclarationOfTypeB //声明类型 class C //声明类型 { static void Main() { ... } }}

命名空间将在第21章详细阐述。3.2 类型是一种模板

既然C#程序就是一组类型声明,那么学习C#就是学习如何创建和使用类型。所以,需要做的第一件事情就是了解什么是类型。

可以把类型想象成一个用来创建数据结构的模板。模板本身并不是数据结构,但它详细说明了由该模板构造的对象的特征。

类型由下面的元素定义:● 名称;● 用于保存数据成员的数据结构;● 一些行为及约束条件。

例如,图3-1阐明了short类型和int类型的组成元素。图3-1 类型是一种模板3.3 实例化类型

从某个类型模板创建实际的对象,称为实例化该类型。● 通过实例化类型而创建的对象被称为类型的对象或类型的实例。

这两个术语可以互换。● 在C#程序中,每个数据项都是某种类型的实例。这些类型可以

是语言自带的,可以是BCL或其他库提供的,也可以是程序员定

义的。

图3-2阐明了两种预定义类型对象的实例化。图3-2 通过实例化类型创建实例3.4 数据成员和函数成员

像short、int和long等这样的类型称为简单类型。这种类型只能存储一个数据项。

其他的类型可以存储多个数据项。比如数组(array)类型就可以存储多个同类型的数据项。这些数据项称为数组元素。可以通过数字来引用这些元素,这些数字称为索引。数组将会在第12章详述。成员的类别

然而另外一些类型可以包含许多不同类型的数据项。这些类型中的数据项个体称为成员,并且与数组中使用数字来引用成员不同,这些成员有独特的名称。

有两种成员:数据成员和函数成员。● 数据成员 保存了与这个类的对象或作为一个整体的类相关的数

据。● 函数成员 执行代码。函数成员定义类型的行为。

例如,图3-3列出了类型XYZ的一些数据成员和函数成员。它包含两个数据成员和两个函数成员。图3-3 类型包含数据成员和函数成员3.5 预定义类型

C#提供了16种预定义类型,如图3-4所示。它们列在表3-1和表3-2中,其中包括13种简单类型和3种非简单类型。

所有预定义类型的名称都由全小写的字母组成。预定义的简单类型包括以下3种。● 11种数值类型。● 不同长度的有符号和无符号整数类型。● 浮点数类型float和double。● 一种称为decimal的高精度小数类型。与float和double不同,decimal类型可以准确地表示分数。decimal类型常用于货币的计算。● 一种Unicode字符类型char。● 一种布尔类型bool。bool类型表示布尔值并且必须为true或

false。说明 与C和C++不同,在C#中的数值类型不具有布尔意义。

3种非简单类型如下。● string,它是一个Unicode字符数组。● object,它是所有其他类型的基类。● dynamic,使用动态语言编写的程序集时使用。图3-4 预定义类型预定义类型的补充

所有预定义类型都直接映射到底层的.NET类型。C#的类型名称就是.NET类型的别名,所以使用.NET的类型名称也能很好地符合C#语法,不过并不鼓励这样做。在C#程序中,应该尽量使用C#类型名称而不是.NET类型名称。

预定义简单类型表示一个单一的数据项。表3-1列出了这些类型,并同时列出了它们的取值范围和对应的底层.NET类型。表3-1 预定义简单类型名含义范围.NET框默称架类型认值System.sbyt8位有符号整数-128~1270SByteeSystem.byt8位无符号整数0~2550ByteeshoSystem.16位有符号整数-32 768~32 7670rtInt16ushSystem.16位无符号整数0~65 5350ortUInt16-2 147 483 648~2 147 System.int32位有符号整数0483 647Int32System.uint32位无符号整数0~4 294 967 2950UInt32-9 223 372 036 854 775 lon808System.64位有符号整数0g~9 223 372 036 854 775 Int64807ulo0~18 446 744 073 709 System.64位无符号整数0ng551 615UInt64System.floa-4538单精度浮点数0.0f~3.4×101.5×10SingletdouSystem.0.-324308双精度浮点数~1.7×105×10bleDouble0dbooSystem.falstrue false布尔型lBooleane\chaSystem.Unicode 字符串U+0000~U+ffffx00rChar00deci小数类型的有效数System.28280m~±7.9×10±1.0×10mal字精度为28位Decimal

非简单预定义类型稍微复杂一些。表3-2所示为非简单预定义类型。表3-2 预定义非简单类型名称含义.NET框架类型所有其他类型的基类,包括简单类objectSystem.Object型0个或多个Unicode字符所组成的序stringSystem.String列dynam在使用动态语言编写的程序集时使无相应的.NET类ic用型3.6 用户定义类型

除了C#提供的16种预定义类型,还可以创建自己的用户定义类型。有6种类型可以由用户自己创建,它们是:● 类类型(class);● 结构类型(struct);● 数组类型(array);● 枚举类型(enum);● 委托类型(delegate);● 接口类型(interface)。

类型通过类型声明创建,类型声明包含以下信息:● 要创建的类型的种类;● 新类型的名称;● 对类型中每个成员的声明(名称和规格)。array和delegate类型

除外,它们不含有命名成员。

一旦声明了类型,就可以创建和使用这种类型的对象,就像它们是预定义类型一样。图3-5概括了预定义类型和用户定义类型的使用。使用预定义类型是一个单步过程,简单地实例化对象即可。使用用户定义类型是一个两步过程:必须先声明类型,然后实例化该类型的对象。

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

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载