第1章 C#入门基础 Microsoft公司是这样描述C#的:“C#是从C和C++派生来的一种简单、现代、面向对象和类型安全的编程语言。C#(读做'Csharp')主要是从C/C++编程语言家族移植过来的,C和C++的程序员会马上熟悉它。C#试图结合Visual Basic的快速开发能力和C++的强大灵活的能力。”。本章将讲解使用C#语言开发的入门知识,主要介绍以下知识点。 .NET Framewrok; 搭建Visual Studio 2008开发环境; 创建第一个控制台应用程序; 创建第一个Windows窗体应用程序。
1.1 C#概述 C#是一种简单的、现代的、面向对象的、类型安全的编程语言。它不但提供了面向对象编程的技术,而且还提供了面向组件编程的支持技术。Visual C# 2008提供了许多方便开发的工具,如高级代码编辑器、方便的用户界面设计器、集成调试器等。开发人员使用这些工具,可以更容易在C#语言3.0版和.NET Framework 3.5版的基础上开发应用程序。
1.1.1 C#语言 C#是一种Microsoft公司设计的、简洁的、类型安全的、面向对象的语言,它松散地基于C/C++语言,并且有很多方面和Java语言类似。开发人员可以使用C#语言来构建在.NET Framework上运行的各种安全、可靠的应用程序。 C#语法表现力强、简单易学、容易上手。通常地,开发人员通过很短的时间的学习,就能够使用C#语言开发高效的程序。C#语法提供了许多强大的功能,如可为空置(null)的值类型、枚举、委托、lambda表达式、直接内存访问等。C#支持泛型类型和方法,进而提供了更为出色的类型安全和性能。特别地,C#还提供了迭代器、语言集成查询(LINQ)表达式等高级功能,使得开发人员可以在C#代码中创建具有查询功能的程序代码。
1.1.2 .NET框架 C#程序必须在.NET Framework上运行。.NET Framework是Windows的一个不可或缺的组件,是一个支持构建、部署和运行下一代应用程序和Web服务的完整Windows组件。.NET Framework能够提供效率极高的、基于标准的多语言(如C#、VB.NET、C++、J#等)环境,能够将现有的应用程序与下一代应用程序和服务集成,并能迅速部署和操作Internet规模的应用程序。.NET Framework主要包括两个组件:公共语言运行库(Common Language Runtime,简称为CLR)和.NET Framework类库(Class Library)。 1.公共语言运行库 2..NET Framework类库 3.公共语言运行库、.NET Framework类库和应用程序的关系 4.语言互操作性 5.C#应用程序执行流程
1.1.3 C#应用程序 C#应用程序包括两种应用程序:控制台(Console)应用程序(1.3小节创建的应用程序就是一个控制台应用程序)和Windows窗体应用程序(1.4小节创建的应用程序就是一个Windows窗体应用程序)。控制台应用程序的界面往往比较简单,而Windows窗体应用程序能够提供丰富的图形界面。 1.控制台应用程序 2.Windows窗体应用程序
1.2 搭建Visual Studio 2008开发环境 本小节介绍搭建开发C#应用程序(如Windows窗体应用程序、ASP.NET网站等)的环境,包括安装Microsoft Visual Studio 2008、配置集成开发环境(IDE)、熟悉集成开发环境(IDE)等内容。 注意:笔者机器的操作系统为Microsoft Windows Server 2003 Enterprise Edition Service Park 2。
1.2.1 安装Microsoft Visual Studio 2008 下面介绍在笔者机器上安装Microsoft Visual Studio Team System 2008简体中文版的操作步骤,具体如下。
1.2.2 配置集成开发环境(IDE) 由于Microsoft Visual Studio 2008集成开发环境(IDE)非常复杂,为了以后能够更加方便地开发各种C#应用程序,在此,特意详细介绍配置Microsoft Visual Studio 2008集成开发环境的方法。
1.2.3 熟悉集成开发环境(IDE) Microsoft Visual Studio 2008集成开发环境包括多个可以停靠或浮动的面板,如“工具箱”、“服务器资源管理器”、“解决方案资源管理器”、“属性”等面板。
1.3 创建第一个控制台应用程序 本节介绍使用Microsoft Visual Studio 2008集成开发环境(IDE)创建第一个控制台应用程序——Sample_01_CA的方法,以及开发Sample_01_CA应用程序所涉及的各种基本技术,如编写C#代码、运行应用程序等。
1.3.1 创建Sample_01_CA控制台应用程序 依次选择“开始”|“所有程序”|“Microsoft Visual Studio 2008”|“Microsoft Visual Studio 2008”命令,打开“起始页 - Microsoft Visual Studio”对话框。单击“最近项目”面板中的“创建”下的“项目”链接,弹出“新建项目”对话框,如图1.24所示。
1.3.2 解决方案资源管理器 创建Sample_01_CA控制台应用程序成功之后,Microsoft Visual Studio 2008集成开发环境(IDE)将为该应用程序创建一个默认类文件,名称为“Program.cs”。打开“解决方案资源管理器”面板,可以查看Sample_01_CA控制台应用程序包含的所有资源和数据,如图1.25所示。
1.3.3 Program.cs文件 双击“解决方案资源管理器”面板中的“Program.cs”节点,打开Program.cs文件。该文件为Sample_01_CA控制台应用程序提供主入口点。
1.3.4 AssemblyInfo.cs文件 首先展开“解决方案资源管理器”面板中的“Properties”节点,然后双击“AssemblyInfo.cs”节点打开AssemblyInfo.cs文件。该文件用来配置Sample_01_CA控制台应用程序的程序集信息。
1.3.5 运行应用程序 按下“F5”按钮或者单击Microsoft Visual Studio 2008集成开发环境中的按钮即可运行Sample_01_CA控制台应用程序。该应用程序运行之后,显示一个黑色的控制台对话框,如图1.26所示。
1.4 创建第一个Windows窗体应用程序 本节介绍使用Microsoft Visual Studio 2008集成开发环境(IDE)创建第一个Windows窗体应用程序——Sample_01_WFA的方法,以及开发Sample_01_WFA应用程序所涉及的各种基本技术,如设计Windows窗体、编写C#代码、配置应用程序、运行应用程序等。
1.4.1 创建Sample_01_WFA Windows窗体应用程序 依次选择“开始”|“所有程序”|“Microsoft Visual Studio 2008”|“Microsoft Visual Studio 2008”命令,打开“起始页 - Microsoft Visual Studio”对话框。单击“最近项目”面板中的“创建”下的“项目”链接,弹出“新建项目”对话框,如图1.27所示。
1.4.2 解决方案资源管理器 创建Sample_01_WFA Windows窗体应用程序成功之后,Microsoft Visual Studio 2008集成开发环境(IDE)将为该应用程序创建一个默认Windows窗体,名称为“Form1.cs”。打开“解决方案资源管理器”面板,可以查看Sample_01_WFA Windows窗体应用程序包含的所有资源和数据,如图1.28所示。
1.4.3 Form1.cs窗体 在“解决方案资源管理器”面板中双击“Form1.cs”节点,打开Form1.cs窗体的设计界面,如图1.29所示。此时,开发人员可以直接将“工具箱”面板中的控件拖放到“Form1.cs”窗体上。
1.4.4 Form1.Designer.cs文件 首先展开“解决方案资源管理器”面板中的“Form1.cs”节点,然后双击“Form1.Designer.cs”节点打开Form1.Designer.cs文件。该文件中的代码为Form1.cs窗体的设计代码,用来描述Form1.cs窗体上的每一个控件。
1.4.5 Form1.cs窗体的代码 右击“解决方案资源管理器”面板中的“Form1.cs”节点,打开Form1.cs窗体的代码文件。该文件保存Form1.cs窗体的事件等设计代码。
1.4.6 Program.cs文件 双击“解决方案资源管理器”面板中的“Program.cs”节点,打开Program.cs文件。该文件为Sample_01_WFA Windows窗体应用程序提供主入口点。
1.4.7 AssemblyInfo.cs文件 首先展开“解决方案资源管理器”面板中的“Properties”节点,然后双击“AssemblyInfo.cs”节点打开AssemblyInfo.cs文件。该文件用来配置Sample_01_WFA Windows窗体应用程序的程序集信息。
1.4.8 运行应用程序 按下“F5”按钮或者单击Microsoft Visual Studio 2008集成开发环境中的“”按钮即可运行Sample_01_WFA Windows窗体应用程序。该应用程序运行之后,显示的第一个对话框为“Form1”对话框,如图1.30所示。
1.5 小结 本章主要介绍了搭建开发Visual Studio 2008集成开发环境,以及C#语言和.NET Framework的概述。其中,读者要着重掌握使用Visual Studio 2008集成开发环境开发第一个控制台应用程序和Windows窗体应用程序的方法。只有这样,才能进行后续的开发。下一章将要介绍使用C#语言如何编写第一个应用程序。
1.6 习题 1.在本章介绍的Sample_01_WFA Windows窗体应用程序之上,实现以下功能。 1.6 习题 1.在本章介绍的Sample_01_WFA Windows窗体应用程序之上,实现以下功能。 (1)添加名称为“Dialog.cs”的窗体到应用程序中。 (2)运行该应用程序。
第2章 C#基本概念 C#语言从1.0版本发展到3.0版本经历了比较长的时间,现在已经是一种比较完善、简单、易学的编程语言。为了读者能够首先对C#语言有一个简单的认识,笔者特意在本章介绍了Hello World应用程序和C#语言的一些常见的基本概念,主要介绍以下知识点。 创建Hello World应用程序; 编译Hello World应用程序; 运行Hello World应用程序; C#程序的概念扩展。
2.1 创建Hello world应用程序 对于C#初学者而言,Hello world应用程序是C#语言入门最好的、简单的示例程序。该程序可以在控制台中显示“Hello world”字符串。下面介绍书写该程序的基本方法。
2.1.1 创建hello.txt文本文件 为了方便初学者真正认识C#程序,我们这里不使用集成开发环境来编写本程序,而是使用记事本来编写程序。新建一个名称为“hello.txt”的文本文件,并打开该文件。
2.1.2 创建HelloWorld类 任何一个C#应用程序都是由类(class)组成。一个C#应用程序可以包括一个类或多个类。类实际上是对某种类型的对象定义变量和方法的原型。它表示对现实生活中一类具有共同特征的事物的抽象,是面向对象程序设计(Object-Oriented Programming,简称为OOP)的基础。 面向对象程序设计指一种程序设计范型,它将对象作为程序的基本单元。在面向对象程序设计中,最为基本的概念是类(class)和对象(object),对象又称为实例。 1.类 2.对象
2.1.3 添加Main()方法 一旦创建一个类之后,但是不为该类添加任何成员,那么该类就是一个空类,即它不能描述世界上的任何一种对象。为了使得类能够描述一种对象,那么就需要为该类添加一些属性和行为。 一个行为就产生一个动作。在类中,使用方法(method)来描述这一行为。也就是说,方法是一个类能做的事情(即一些计算或操作),但是并没有做这事情。作为一条狗而言,它是会吠叫、会坐下、会吃。因此,为了能够使用Dog类描述狗,那么就需要在该类中定义以下3个方法。 Bark(),吠叫。 Sit(),坐下。 Eat(),吃。
2.1.4 调用WriteLine()方法 在Dog类中,虽然定义了狗的3个行为:吠叫、坐下和吃,但是并没有使这3个行为发生。如果想要芊芊这一条狗吠叫,那么就需要一个主动的动作使得芊芊吠叫。这一个主动的动作就是调用该行为对应的方法,即通过调用方法使得该方法对应的行为发生。
2.1.5 引入System命名空间 世界上存在很多狗,而且一些狗的名字也相同。譬如,张三家的狗叫芊芊,而李四家的狗也叫芊芊。那么如何区分这两家的狗呢?自然,称呼张三家的狗可能是“张三家的芊芊”,称呼李四家的狗可能是“李四家的芊芊”。通过这种方式,就能够区分张三家和李四家的芊芊了。
2.1.6 整理Hello world应用程序的代码 经过上述步骤之后,就已经书写了一个完整的C#应用程序——Hello world应用程序,它的完整的程序代码如下。 using System; class HelloWorld { static void Main() Console.WriteLine("Hello, World"); }
2.2 编译和运行Hello World应用程序 2.1小节仅仅书写了Hello world应用程序的代码。如果要将这一段程序代码成为一个可以执行的文件,则需要使用Microsoft C#编译器编译这一段代码。
2.3 C#程序的概念扩展 在2.1小节中介绍了C#面向对象程序设计的一些基本概念,如类、对象、实例、属性、方法、调用方法等。除了上述这些概念之外,还有一些比较常用的概念,如继承性、多态性等。 1.继承性 2.多态性 3.接口
2.4 小结 本章主要介绍了“Hello world”应用程序,包括创建Hello World应用程序、编译Hello World应用程序、运行Hello World应用程序和分析Hello World应用程序。其中,读者需要着重掌握使用记事本创建Hello World应用程序的方法。下一章将介绍C#的类型。
2.5 习题 使用记事本撰写一个名称为“Test_02”的C#应用程序的代码,并将此代码编译为一个名称为“Test_02.exe”的可执行文件。Test_02应用程序在控制台显示“This is a C# program.”字符串。
第3章 类型 类型是C#语言中最为基本的概念之一。不同类型的变量将拥有不同的数据存储方式和操作方法。C#语言的类型系统是统一的,它可以把任何类型的值都按照对象来处理。本章将讲解C#语言中各种类型,主要介绍以下知识点 值类型; 引用类型; 装箱; 拆箱。
3.1 类型概述 C#语言中的每一个类型都直接或间接派生于object类型,即object类型是C#语言所有类型的最终基类型。C#语言的类型可以分为以下3种类型。 值类型(value-type),它的变量直接包含其数据。 引用类型(reference-type),它的变量只存储对其数据的引用(即访问其数据的访问地址)。引用类型的变量又称为对象(object)。 指针类型(point-type),和C、C++语言中的指针类似,而且只能用作在不安全代码中。由于在C#编程中很少使用指针类型,因此,在此不做详细介绍。
3.2 值类型 值类型要么是结构类型,要么是枚举类型。值类型的变量直接包含其数据,而且其值不可能为null。在操作值类型的变量时,只会影响该变量的数据,而不会影响另外一个变量的值。所有的值类型都直接或间接派生于System.ValueType类型。 值类型包括结构类型、枚举类型、布尔类型、自定义结构类型、sbyte、byte、char、short、ushort、int、uint、long、ulong、float、double和decimal类型。其中,C#语言提供了一种被称为“简单类型(simple type)”的预定义结构类型。这些类型通过C#保留字标识,如char、int等。本节将详细介绍值类型的知识点。
3.2.1 System.ValueType类型 所有值类型都直接或间接从System.ValueType类隐式继承而来,并且任何类型不能从值类型派生而来。System.ValueType本身是一个类,它只包含以下3个方法。 Equals(),判定当前实例与指定的对象是否相等。 GetHashCode(),返回当前实例的哈希代码。该哈希代码用于哈希表(一种数据结构)的散列运算。 ToString(),返回当前实例的完全限定类型名称。
3.2.2 整数类型 整数类型包括9种类型,如sbyte、byte、short等。它们的具体说明、.NET Framework中的名称和取值范围如表3.1所示。 1.int类型 2.long类型 3.char类型 类型 描述 .NET Framework中的名称 取值范围 sbyte 有符号8位整数 System.SByte -128~127 byte 无符号8位整数 System.Byte 0~255 short 有符号16位整数 System.Int16 -32768~32767 ushort 无符号16位整数 System.UInt16 0!65535 int 有符号32位整数 System.Int32 -2147483648~2147483647 uint 无符号32位整数 System.UInt32 0~4294967295 long 有符号64位整数 System.Int64 -9223372036854775808~9223372036854775807 ulong 无符号64位整数 System.UInt64 0~18446744073709551615 char System.Char 0~65535,16位的Unicode字符。
3.2.3 浮点型 C#语言包括两种浮点型:float和double。float类型表示32位的单精度浮点数,它的取值范围为±1.5e-45~±3.4e38。double类型表示64位的双精度浮点数,它的取值范围为±5.0e-324~±1.7e308。浮点数包括以下3种特殊的值。 正零和负零 正无穷大和负无穷大 非数字(Not-a-Number)值
3.2.4 decimal类型 decimal类型表示128位的数值,取值范围为±1.0e-28~±7.9e28,特别适用于财务计算和货币计算。和float类型一样,在书写decimal类型的值时,需要在数值后添加后缀m,否则编译出错。 与浮点型相比,decimal类型具有较高的精度,但取值范围较小。因此,从浮点型到decimal类型的转换可能会产生溢出异常,而从decimal类型到浮点型的转换则可能导致精度损失。正是由于这些原因,所以,在浮点型和decimal类型之间不存在隐式转换。如果要转换浮点型到decimal类型,则必须使用强制转换方法。
3.2.5 bool类型 bool类型表示布尔逻辑量。它只包含两个值:true和false,而且这两个值意义恰好相反。
3.2.6 枚举类型 枚举(enum)类型也是一种值类型,它具有命名常量的独特的类型。每个枚举类型都有一个基础类型,该基础类型必须为byte、sbyte、short、ushort、int、uint、long或ulong。其中,默认的基础类型为int。 枚举类型一般包含一个或多个枚举值,每一个枚举值之间用逗号(,)分隔。枚举值又称为枚举数,它的默认基础类型为int。默认情况下,第一个枚举数的值为0,后面的每一个枚举数的值依次增1。
3.2.7 结构类型 结构类型也是一种值类型,它可以声明常量、字段、方法、属性、索引器、运算符、实例构造函数、静态构造函数和嵌套类型。有关结构类型的知识点将在第9章中进行详细介绍。
3.2.8 实例一:把整数转换为二进制数 【实例3-1】实现把整数转换为二进制数的功能。该功能由ConvertIntToBinary(int n)静态函数实现,n参数表示被转换的整数,该函数返回二进制数的字符串形式。
3.2.9 实例二:把二进制数转换为整数 【实例3-2】实现把二进制数转换为整数的功能。该功能由ConvertBinaryToInt(string binary)静态函数实现,binary参数表示被转换的二进制数的字符串形式,该函数返回一个整数。
3.3 引用类型 引用类型主要包括6种类型:object类型、string类型、类类型、数组类型、接口类型和委托类型。引用类型变量的值是对该类型的某个实例的一个引用。其中,类型的实例被称为对象。在引用类型中,存在一个很特殊的值:null。null能够兼容所有的引用类型,表示“每一被引用的实例”。本节将详细介绍引用类型的知识点。
3.3.1 对象类型 对象(object)类型是C#类型系统中所有其他类型的最终基类。C#中的每种类型都是直接或间接从object类类型派生的。因此,C#中的任何类型都可以转换为object类型。
3.3.2 字符串类型 字符串(string)类型是直接从object继承而来的类类型,它对应着.NET Framework中的System.String类型。
3.3.3 类类型 类(class)类型是C#中最常用的类型。它是一个数据结构,能够定义数据成员、函数成员和嵌套类型等内容。其中,数据成员包括常量和字段,函数成员包括方法、属性、事件、索引器、运算符、实例构造函数、析构函数和静态构造函数。 特别地,类类型还支持一种被称为“继承”的机制。继承是指派生类可用来扩展和专门化基类的一种机制。有关类类型的知识点将在第8章中进行详细介绍。
3.3.4 数组类型 数组(Array)是一种数据结构,它可以将多个类型相同的元素组合为一个整体,从而通过数组统一访问或操作这些元素。数字可以通过计算索引来访问数组中的每一个元素。每一个元素的类型称为数字的元素类型。
3.3.5 接口类型 接口(interface)类型和类类型非常相似。它也是一个数据结构,能够声明数据成员和函数成员。其中,数据成员主要包括属性,函数成员包括方法和事件。
3.3.6 委托类型 委托(delegate)也是一种数据结构,它能够引用一个或多个方法。特别地,对于实例方法,它还能够引用这些方法所对应的对象实例。读者如果熟悉C++中的函数指针,那么就不难理解委托这一概念了。 委托类型类似于C++中的函数指针,但是它是类型安全的。委托类型能够将方法作为参数进行传递,并且还可以定义回调方法。
3.4 装箱和拆箱 引用类型总是分配在托管堆上,而值类型总是分配在堆栈上。有时,程序需要获取指向值类型的引用。此时,需要将值类型转换为引用类型,这一操作被称为装箱。反之,把引用类型转换为值类型称为拆箱。 装箱和拆箱是C#的类型系统中两个很重要的概念,它在值类型和引用类型之间的架起了一座桥梁。通过装箱和拆箱操作,可以将任何值类型的变量的值转换为引用类型的变量的值。反之,也可以进行转换。特别地,有了装箱和拆箱操作,就可以将C#类型系统中的任何类型的值最终都可以按对象来处理。
3.4.1 装箱 装箱是指将值类型隐式转换为引用类型。对于值类型而言,装箱的具体操作为:首先分配一个对象实例,然后将值类型的值复制到该实例中。装箱前后不是同一个实例。对于引用类型而言,装箱前后都共享同一个实例。
3.4.2 拆箱 拆箱是指将引用类型隐式转换为值类型。拆箱的具体操作包括以下2个步骤。 3.4.2 拆箱 拆箱是指将引用类型隐式转换为值类型。拆箱的具体操作包括以下2个步骤。 (1)检查该对象实例是否为给定值类型的一个装了箱的值。 (2)将值从实例中复制出来。
3.5 小结 本章主要介绍了C#语言的类型系统的基础知识,如值类型、引用类型、类型转换、装箱、拆箱等。其中,读者要着重掌握值类型和引用类型,为后续编写C#程序代码奠定基础。下一章将要介绍C#语言中的变量。
3.6 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_03”的控制台应用程序,并实现以下功能。 3.6 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_03”的控制台应用程序,并实现以下功能。 (1)将名称为“class1.cs”的文件添加到该应用程序中。 (2)创建一个整型变量vint和一个字符串变量vstring,将vint变量转换为字符串,将vstring变量转换为一个整数。
第4章 变量 变量是C#语言中最为基本的概念之一,它表示存储位置。每一个变量的值由其类型确定。本章将讲解C#语言中各种变量,主要介绍以下知识点。 变量概述; 变量分类; 变量赋值; 使用值参数传递数据; 使用ref参数传递数据; 使用out参数传递数据; 变量转换。
4.1 变量概述 在C#语言中,变量表示存储位置。每一个变量都具有一个类型,该类型确定变量存储的内容。对于两个变量而言,如果它们的值相同,但是类型不同,那么该变量存储的值是不相同的。 声明一个变量之后,该变量可能具有初始值,也可能不具有初始值。如果变量具有初始值,则称之为初始已赋值(initially assigned)。如果变量不具有初始值,则称之为初始未赋值(initially unassigned)。 如果是第一次明确指定变量的值,则称之为变量的初始化。如果是初始未赋值变量,必须经过初始化之后,才能够被使用。
4.2 变量分类 C#语言定义了7种不同类别的变量:静态变量、实例变量、数组元素、值参数、引用参数、输出参数和局部变量。本小节将详细介绍这7种类别的变量。
4.2.1 静态变量 静态变量(static variable)是指使用static修饰符声明的变量。静态变量总是在包含了它的那个类型的静态构造函数(第8章)执行之前就存在了,在关联的应用程序域终止时终止。
4.2.2 实例变量 实例变量(instance variable)和静态变量相对应。实例变量是指未使用static修饰符声明的变量。实例变量包括两种类型的变量:类的实例变量和结构的实例变量。 1.类的实例变量 2.结构的实例变量
4.2.3 局部变量 顾名思义,局部变量(local variable)是在应用程序的某一段时间内存在。局部变量可以声明在块(block)、for语句、switch语句和using语句中,即局部变量是通过“local-variable-declaration”来声明的。
4.2.4 值参数 对于一个函数成员而言,它都存在一个参数列表(紧跟在函数成员名称之后的小括弧中)。当然,该参数列表可以是空,也可以包含一个或多个参数,多个参数之间使用逗号(,)分隔。 在声明参数时,可以不使用修饰符,也可以使用ref或out修饰符。值参数(value parameter)是指未使用ref或out修饰符声明的参数。
4.2.5 ref参数 引用参数(reference parameter)是值使用ref修饰符声明的参数。引用参数和值参数最大的一个区别在于:在函数成员中,函数成员为值参数分配了一个新的存储位置,而引用参数仍然使用其基础变量的存储位置。即引用参数和其基础变量操作了同一个变量,而值参数和其基础变量是操作了两个不同变量,而且不互相影响。
4.2.6 out参数 输出参数(output parameter)是值使用out修饰符声明的参数。输出参数和值参数最大的一个区别在于:在函数成员中,函数成员为值参数分配了一个新的存储位置;输出参数不创建新的存储位置,而是使用基础变量的存储位置。因此,输出参数的值总是与基础变量相同。 简而言之,基础变量实际上是分配了一个存储位置,在调用包含out参数的函数成员时,该函数成员将在这一个存储位置存储新的值,并修改基础变量的值。
4.2.7 数组元素 数组元素是指作为函数成员参数的数组(第8章)的元素,它总是在创建数组实例时开始存在,在没有对该数组实例的引用时停止存在。每个数组元素的初始值都是其数组元素类型的默认值。
4.3 变量赋值 变量赋值是指给变量指定某一个明确的值,如“int i = 2008;”语句在声明i变量的同时给该变量赋值为2008。在函数成员可执行代码中的给定位置,如果编译器可确定变量已自动初始化或已成为至少一个赋值的目标,则称该变量已明确赋值(definitely assigned)。
4.4 实例一:使用值参数传递数据 【实例4-1】演示了使用值参数传递数据的方法。该功能由static int CountSum(int i,int j)静态函数实现,i和j参数均为值参数。CountSum(int i,int j)函数返回i和j参数的值增1之后的和。
4.5 实例二:使用ref参数传递数据 【实例4-2】演示了使用ref参数传递数据的方法。该功能由static int RefCountSum(ref int i,ref int j)静态函数实现,i和j参数均为ref参数。RefCountSum(ref int i,ref int j)函数返回i和j参数的值增1之后的和。
4.6 实例三:使用out参数返回数据 【实例4-3】演示了使用out参数传递数据的方法。该功能由static void OutCountSum(int i,int j,out int sum)静态函数实现,i和j参数均为的值参数,sum参数为out参数。OutCountSum(int i,int j,out int sum)函数本身不返回值,但是用sum参数保存i和j参数的值增1之后的和。
4.7 变量转换 转换(conversion)使一种类型的表达式可以被视为另一种类型。变量转换(variable conversion)使一种类型的变量可以被视为另一种类型。转换可以分为隐式转换(implicit conversion)和显式转换(explicit conversion)。如果在转换时,需要添加强制转换的类型,那么该转换为显式转换。本小节将介绍变量转换的知识点。
4.7.1 隐式转换 隐式转换是指不需要添加强制转换的类型的转换。常用的隐式转换包括以下几种。 4.7.1 隐式转换 隐式转换是指不需要添加强制转换的类型的转换。常用的隐式转换包括以下几种。 标识转换,在同一类型内进行转换,它能够使已具有所需类型的实体可被认为是可转换的。 隐式数值转换,如从int类型转换为long类型等。 隐式枚举转换,将数值转换为枚举类型。 隐式引用转换,如引用类型转换为object类型等。 装箱转换,如值类型转换为object类型等。 隐式常量表达式转换,如将int类型转换为uint类型等。 用户定义的隐式转换,包括以下3个步骤:一个标准的隐式转换;执行用户定义的隐式转换运算符;另一个标准的隐式转换。
4.7.2 显示转换 显式转换是指需要添加强制转换的类型的转换。常用的显式转换包括以下几种。 4.7.2 显示转换 显式转换是指需要添加强制转换的类型的转换。常用的显式转换包括以下几种。 显式数值转换,如long类型转换为int类型等。 显式枚举转换,如int类型转换为枚举类型等。 显式引用转换,如object类型转换为引用类型等。 显式接口转换,如object类型转换为接口类型等。 拆箱转换,如object类型转换为值类型等。 用户定义的显式转换, 包括以下3个步骤:一个标准的隐式转换;执行用户定义的显式转换运算符;另一个标准的隐式转换。
4.8 小结 本章主要介绍了C#语言中的变量的基础知识,如变量概述、变量分类、变量赋值、值参数、ref参数、out参数、变量转换等。其中,读者要着重掌握变量赋值、值参数、ref参数、out参数和变量转换,为后续编写C#程序代码奠定基础。下一章将要介绍C#语言中的表达式和运算符。
4.9 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_04”的控制台应用程序,并实现以下功能。 4.9 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_04”的控制台应用程序,并实现以下功能。 (1)将名称为“class1.cs”的文件添加到该应用程序中。 (2)创建一个名称为“ValueF”的方法,且该方法使用值参数value。 (3)创建一个名称为“RefF”的方法,且该方法使用ref参数value。 (4)创建一个名称为“OutF”的方法,且该方法使用out参数value。
第5章 表达式和运算符 表达式是C#语言组成的重要元素之一,它是可以计算且结果为单个值、对象、方法或命名空间的代码片段。表达式也可以包含文本值、方法调用、运算符及其操作数,或简单名称。简单的说,表达式是一个由操作数和运算符组成的序列。本章将讲解C#语言中的表达式和运算符,主要介绍以下知识点。 表达式分类; this、base和new关键字; 运算符; 运算检查; 运算符重载。
5.1 表达式 表达式是一个由操作数(operand)和运算符(operator)构成的序列。运算符指定操作数的运算规则,即指示对表达式中的操作数进行什么样的运算。本节将介绍表达式的知识点。
5.1.1 表达式分类 在C#语言中,可以把表达式分为以下9种类别,如表5.1所示。 表达式类型 说明 值 每一个值都有关联的类型。 变量 5.1.1 表达式分类 在C#语言中,可以把表达式分为以下9种类别,如表5.1所示。 表达式类型 说明 值 每一个值都有关联的类型。 变量 每一个变量都有关联的类型。如果该变量存在了相关的类型,则称该变量为已声明类型的变量。 命名空间 C#程序是利用命名空间组织起来的。 类型 指定变量数据的存储方式和操作方法。 方法组 表示一组方法,并可以通过实例调用方法组中的方法。 属性访问 每个属性访问都有关联的类型,即该属性的类型。 事件访问 每个事件访问都有关联的类型,即该事件的类型。 索引器访问 每个索引器访问都有关联的类型,即该索引器的元素类型。 Nothing 出现在调用一个具有void返回类型的方法时。
5.1.2 this关键字 this关键字可以用来引用类的当前实例,还可以用作扩展方法的第一个参数的修饰符。this关键字存在以下3种常用用法。 1.限定名称相同的成员 2.将对象本身作为参数 3.声明索引器
5.1.3 base关键字 base关键字用于从派生类中访问基类的成员,主要存在以下2种用法。 调用基类上已被其他方法重写的方法。 指定创建派生类实例时应调用的基类构造函数。 base关键字之后一般跟着“.”标记和一个标识符或一个用方括号括起来的表达式列表。
5.1.4 new关键字 new关键字可以作为new运算符、new修饰符或new约束。 1.new运算符 2.new修饰符 3.new约束
5.2 运算符 运算符是表达式很重要的一部分,它指示对表达式中的操作数进行什么样的运算,如+、-、*、/、%等。根据运算符所需操作数的个数,可以把运算符分为以下3类。本节介绍运算符的知识点。 一元运算符,只带有一个操作数并使用前缀表示法(如--x)或后缀表示法(如x++),如++、--等运算符。 二元运算符,带有两个操作数并且全都使用中缀表示法(如x+y),如+、-、*、/等运算符。 三元运算符,带有3个操作数并使用中缀表示法,如?: 运算符。
5.2.1 运算符优先级 算术表达式是最为常见的一种表达式。它由操作数和运算符组成,而且这些运算符之间是存在一定优先级的,如*运算符的优先级就大于+运算符的优先级。C#语言中的运算符一样,也存在优先级。在计算表达式的值时,也必须遵循运算符的优先级的规则。
5.2.2 一元运算符 +、-、!、~、++x、--x和(T)x被称为一元运算符。其中,(T)x运算符为强制转换运算符,它可以将一种类型转换为另外一种类型。+、-和~运算符分别表示一元加运算、一元减运算和按位求补运算。下面详细介绍!、++x、--x和(T)x运算符的使用方法。 1.++运算符 2.--运算符 3.!运算符 4.(T)x运算符
5.2.3 算术运算符 *、/、%、+和–运算符称为算术运算符,它们分别表示乘法、除法、余数、加法和减法运算。语法如下。 5.2.3 算术运算符 *、/、%、+和–运算符称为算术运算符,它们分别表示乘法、除法、余数、加法和减法运算。语法如下。 left expression operator right expression left expression和right expression分别表示左操作数和右操作数,operator表示运算符,可以为*、/、%、+和–。
5.2.4 逻辑运算符 &、^和|运算符称为逻辑运算符。&运算符计算两个操作数的按位逻辑AND,|运算符计算两个操作数的按位逻辑OR,^运算符计算两个操作数的按位逻辑XOR。语法如下。 left expression operator right expression left expression和right expression分别表示左操作数和右操作数,operator表示运算符,可以为&、^和|。
5.2.5 条件运算符 ?:运算符称为条件运算符,它是C#语言中唯一的一个三元运算符,语法如下。 5.2.5 条件运算符 ?:运算符称为条件运算符,它是C#语言中唯一的一个三元运算符,语法如下。 条件表达式 ? resulta : resultb; 该表达式首先计算条件表达式的值。如果条件表达式的值为真,则resulta的值,并成为运算结果。否则计算resultb,并成为运算结果。
5.2.6 条件逻辑运算符 &&和||运算符称为条件逻辑运算符。&&运算符为逻辑与运算符,它计算左右操作数的逻辑与。||运算符为逻辑或运算符,它计算左右操作数的逻辑或。语法如下。 left expression operator right expression left expression和right expression分别表示左操作数和右操作数,operator表示运算符,可以为&&和||。
5.2.7 移位运算符 <<和>>运算符被称为移位运算符。<<运算符表示左移位,>>运算符表示右移位。语法如下: erpression operator count; expression表示被移位的表达式,count表示移动的位数,operator表示运算符,可以为<<和>>。
5.2.8 关系和类型测试运算符 ==、!=、<、>、<=、>=、is和as运算符称为关系和类型测试运算符。语法如下: left expression operator right expression left expression和right expression分别表示左操作数和右操作数,operator表示运算符,可以为==、!=、<、>、<=、>=、is和as。其中,==、!=、<、>、<=和>=运算符为比较运算符,它们的具体计算方法如下: x == y,如果x等于y,则为true,否则为false。 x != y,如果x不等于y,则为true,否则为false。 x < y,如果x小于y,则为true,否则为false。 x > y,如果x大于y,则为true,否则为false。 x <= y,如果x小于等于y,则为true,否则为false。 x >= y,如果x大于等于y,则为true,否则为false。
5.2.9 赋值运算符 =、*=、/=、%=、+=、-=、<<=、>>=、&=、^=和|=运算符被称为赋值运算符,它们能够为变量、属性、事件或索引器元素赋新值。语法如下: left expression operator right expression left expression和right expression分别表示左操作数和右操作数,operator表示运算符,如=、*=、/=等。
5.3 实例一:使用checked和unchecked运算符检查运算 【实例5-1】演示了使用checked和unchecked运算符检查运算的方法。该功能由static void CheckCompute()静态函数实现。
5.4 实例二:复数运算符重载 在C#语言中,所有一元和二元运算符都具有可自动用于任何表达式的预定义实现。除了预定义运算操作之外,还可通过在类或结构中设置operator声明来引入用户定义的运算操作。这一技术被称为运算符重载。 注意:用户定义的运算符操作的优先级总是高于预定义运算符操作的优先级。 运算符重载可以分为一元运算符重载和二元运算符重载,重载方法如表5.3所示。 运算符表示法 重载函数表示法 说明 op x operator op(x) op为运算符 x op x op y operator op(x,y)
5.5 小结 本章主要介绍了C#语言中的表达式和运算符,如表达式分类、this关键字、base关键字、new关键字、运算符、运算符重载等。其中,读者要着重掌握表达式、运算符和运算符重载,为后续编写C#程序代码奠定基础。下一章将要介绍C#语言中的语句。
5.6 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_05”的控制台应用程序,并实现以下功能。 5.6 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_05”的控制台应用程序,并实现以下功能。 (1)将名称为“class1.cs”的文件添加到该应用程序中。 (2)创建一个名称为“Sum”的方法,且在该方法中使用checked和unchecked运算符检查计算两个数的和的运算操作。
第6章 语句 和其他编程开发语言(如C、C++等)一样,C#语言也是由各种各样的语句有序构建而成的。语句可以声明局部变量或常量,调用方法,创建对象,将值赋予变量、属性或字段等。一般地,语句以;(分号)终止。本章将讲解C#语言中的各种语句,主要介绍以下知识点。 基本语句; 跳转语句; 选择语句; 迭代语句; 其他语句。
6.1 语句概述 和其他程序开发语言一样,C#语言也提供了多种语句。C#语言的语句可以分为以下3个大类: 6.1 语句概述 和其他程序开发语言一样,C#语言也提供了多种语句。C#语言的语句可以分为以下3个大类: 标记语句,给语句加上一个标签作为前缀。 声明语句,用来声明局部变量或常量 嵌入语句,能够嵌入到本身语句或其他语句中执行的语句。
6.2 基本语句 C#语言包含多种常用的基本语句,如空语句、标记语句、表达式语句、声明语句、块等。本节将详细介绍创建这些语句的方法。
6.2.1 空语句 顾名思义,空语句(empty statement)不包括任何实际性语句,它什么都不做。空语句的语法形式如下: ; 6.2.1 空语句 顾名思义,空语句(empty statement)不包括任何实际性语句,它什么都不做。空语句的语法形式如下: ; 当在要求有语句的上下文中不执行任何操作时,使用空语句
6.2.2 标记语句 标记语句(labeled statement)可以给语句加上一个标签作为前缀,它可以出现在块(第6.2.5节)中,但是不允许它们作为嵌入语句。标记语句的语法形式如下: identifier : statement; identifier为标签的名称。在同一个块中,不能存在两个同名的标签,否则会产生编译错误。statement表示被标签标记的语句。
6.2.3 表达式语句 表达式语句是C#语言程序代码中最为常见的一种语句,它用来计算所给定表达式的值,而且由该表达式计算的值将被丢弃。实际上,表达式的值只是一个中间结果。表达式语句包括以下7类语句: 赋值表达式,如“i = 2008;”等。 调用表达式,如“Count();”等。 创建对象表达式,如“object o = new object();”等。 前缀递减表达式,如“-- i”等。 前缀递增表达式,如“++ i”等。 后缀递减表达式,如“i --”等。 后缀递增表达式,如“i ++”等。
6.2.4 声明语句 声明语句用来声明局部变量或常量,它可以出现在块(第6.2.5节)中,但不允许它们作为嵌入语句使用。声明语句包括声明局部变量语句和声明局部常量语句。声明局部变量语句用来声明一个局部变量。
6.2.5 块 块(block)用于编写多条语句,并且可以将整个块看成一个单个语句。块的语法形式如下: { statement-list } 6.2.5 块 块(block)用于编写多条语句,并且可以将整个块看成一个单个语句。块的语法形式如下: { statement-list } statement-list为一个语句列表,它是可选的。如果不存在statement-list,则称该块是空的。语句列表是由一个或多个顺序编写的语句组成。
6.3 跳转语句 跳转语句(jump statement)用于无条件地转移程序的控制,它包括以下5种跳转语句: 6.3 跳转语句 跳转语句(jump statement)用于无条件地转移程序的控制,它包括以下5种跳转语句: break语句,用于退出直接封闭它所在的switch(第6.4.2小节中介绍)、while(第6.5.3小节中介绍)、do(第6.5.4小节中介绍)、for(第6.5.1小节中介绍)或foreach语句(第6.5.2小节中介绍)。 continue语句,用于开始直接封闭它的while、do、for或foreach语句的一次新循环。 return语句,一般用于函数成员的返回操作,即将控制返回到函数成员的调用方。 throw语句,用于产生一个异常。 goto语句,跳转到指定的标签位置。
6.3.1 break语句 break语句用于退出直接封闭它所在的switch、while、do、for或foreach语句。它的语法形式如下: break; 注意:break语句只能用在switch、while、do、for或foreach语句中,否则发生编译时错误。 如果break语句位于多层嵌套的switch、while、do、for或foreach语句中,break语句只能应用于最里层的语句。
6.3.2 continue语句 continue语句用于开始直接封闭它的while、do、for或foreach语句的一次新迭代。它的语法形式如下: continue; 注意:continue语句只能用在while、do、for或foreach语句中,否则发生编译时错误。 如果continue语句位于多层嵌套的while、do、for或foreach语句中,continue语句只能应用于最里层的语句。
6.3.3 return语句 return语句一般用于函数成员的返回操作,即将控制返回到函数成员的调用方。它的语法形式如下: return expressionopt; expressionopt为返回值的表达式,它是一个可选表达式。return语句存在以下两种形式: 不带expressionopt表达式的return语句,只能用在返回类型为void的函数成员、属性的set访问器(第8章)、事件的add和remove访问器(第8章)、实例构造函数(第8章)、静态构造函数(第8章)或析构函数(第8章)中。 带expressionopt表达式的return语句,只能用在返回类型不是void的函数成员、属性的get访问器(第8章)。expressionopt表达式必须能够隐式转换为其所在函数成员的返回类型。
6.3.4 throw语句 throw语句用来引发一个异常。它的语法形式如下: throw expressionopt; expressionopt为返回值的表达式,它是一个可选表达式。和return语句一样,throw语句也分为以下两种形式: 不带表达式的throw语句,只能用在catch块(第6.6.1节)中,它将重新引发当前正由该catch块处理的那个异常。 带表达式的throw语句,通过expressionopt表达式产生异常的值。而且,该异常的值的类型必须为System.Exception类型或者从System.Exception类派生的类型。
6.4 选择语句 选择语句是指根据表达式的值从若干个给定的语句中选择一个来执行的语句。选择语句包括if语句和switch语句。每一个if语句的选择支只有2个,而每一个switch语句的选择支可以为1个或多个。本节将详细介绍if语句和switch语句。
6.4.1 if语句 if语句能够根据布尔表达式的值选择要执行的语句,它存在以下2种语法形式。 if(布尔表达式) 嵌入语句; if(布尔表达式) 嵌入语句1; else嵌入语句2;
6.4.2 switch语句 switch语句比if语句更加灵活,它可以存在1个或多个可执行的选择支。它的语法形式如下: { case常量表达式1:语句块1; case常量表达式2:语句块2; … default: 语句块n; }
6.5 迭代语句 迭代语句是指可以重复执行嵌入语句的语句,包括for语句、foreach语句、while语句和do语句。本节将详细介绍这4中迭代语句。
6.5.1 for语句 for语句首先计算一个初始化表达式序列,然后,当某个条件为真时,重复执行相关的嵌入语句并计算一个迭代表达式序列。for语句的语法形式如下: for (初始化表达式; 条件表达式; 迭代表达式) 嵌入语句;
6.5.2 foreach语句 foreach语句用于枚举一个集合的元素,并对该集合中的每个元素执行一次相关的嵌入语句。foreach语句的语法形式如下: foreach (类型 迭代变量 in 表达式) 嵌入语句;
6.5.3 while语句 while语句能够按照不同条件执行一个嵌入语句零次或多次,它的语法形式如下:
6.5.4 do语句 do语句和while语句非常相似,它能够按照不同条件执行一个嵌入语句一次或多次。它的语法形式如下: 如果布尔表达式的值为true,则执行嵌入语句。do语句按照如下规则执行,执行的流程图如图6.7所示。
6.6 其他语句 其他语句主要包括try语句、using语句、lock语句、checked语句、unchecked语句等。本节将详细介绍这些语句的使用方法。
6.6.1 try语句 try语句提供一种机制,可以用来捕捉在块的执行期间发生的各种异常。此外,try语句还能指定一个代码块,并保证当控制离开try语句时,总是先执行该代码。 一个try语句可能包含try块、catch块和finally块。try块一般包含需要恢复或清理操作的代码,即有可能发生异常的代码。catch块一般包括出现异常时需要执行的响应代码。finally块一般包括确保一定执行的代码,如资源清理操作等。 对于一个try语句而言,try块是必须的,而且只能是一个,catch块和finally块不是必须的。一个try语句存在以下3种形式: 一个try块,后跟一个或多个catch块。 一个try块,后跟一个finally块。 一个try块,后跟一个或多个catch块,后面再跟一个finally块。
6.6.2 using语句 using语句用来定义一个范围,并在该范围之外释放一个或多个对象,即用于获取一个或多个资源,并执行一个语句,然后释放该资源。它的语法形式如下: using (resource-acquisition) embedded-statement resource-acquisition用于获取一个或多个资源,表示该资源的对象必须实现了System.IDisposable的类或结构。embedded-statement为一个嵌入语句,当using语句获取其资源之后,将执行该嵌入语句。 执行using语句时,一般包括3个步骤:获取资源、使用资源和释放资源。using语句最常见的形式如下所示。 using (ResourceType resource = expression) statement
6.6.3 lock语句 lock语句用于首先获取某个给定对象的互斥锁,即对该对象进行加锁。然后执行一个语句,最后释放该锁。它的语法形式如下: lock (expression) embedded-statement expression表示被加锁的对象,且必须为引用类型的对象;embedded-statement表示加锁过程中执行的语句。
6.6.4 checked和unchecked语句 checked语句和unchecked语句用于控制整型算术运算和转换的溢出检查上下文。checked语句和unchecked语句完全等效于checked运算符和unchecked运算符(第5.3节)。不同的是,checked语句和unchecked语句用于块,而不是表达式。
6.7 实例一:判断闰年 【实例6-1】演示了使用if语句判断指定的年份是否为闰年。该功能由IsLeapYear(int year)静态函数(year参数类型为int,表示年份)实现。其中,判断指定的年份是否为闰年的规则如下。 能被4整除而不能被100整除的年份,则是闰年。 能被400整除的年份,则是闰年。 不满足上述任何一个条件的年份,则不是闰年。
6.8 小结 本章主要介绍了C#语言中的语句,如基本语句、跳转语句、选择语句、迭代语句、其他语句等。其中,读者要着重掌握基本语句、跳转语句、选择语句和迭代语句,为后续编写C#程序代码奠定基础。下一章将要介绍C#语言中的命名空间。
6.9 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_06”的控制台应用程序,并实现以下功能。 6.9 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_06”的控制台应用程序,并实现以下功能。 (1)将名称为“class1.cs”的文件添加到该应用程序中。 (2)创建一个名称为“IFStatement”的方法,且在该方法中使用if语句。 (3)创建一个名称为“SwitchStatement”的方法,且在该方法中使用switch语句。 (4)创建一个名称为“ForStatement”的方法,且在该方法中使用for语句。 (5)创建一个名称为“ForeachStatement”的方法,且在该方法中使用foreach语句。 (6)创建一个名称为“WhileStatement”的方法,且在该方法中使用while语句。 (7)创建一个名称为“DoStatement”的方法,且在该方法中使用do语句。 (8)创建一个名称为“TryStatement”的方法,且在该方法中使用try语句。
第7章 命名空间 C#语言的程序是利用命名空间(namespace)组织起来的,它为C#语言的类型系统提供唯一的完全限定名称。命名空间既用作程序的“内部”组织系统,也用作“外部”组织系统(相对于其他程序而言的,一种用来公开程序本身所拥有元素的方法)。本章将讲解C#语言的命名空间,主要介绍以下知识点。 声明命名空间; .(点号)运算符; ::(双冒号)运算符; using指令; .NET Framework常用命名空间。
7.1 命名空间概述 命名空间(namespace)是一种用于组织C#程序代码中的不同类型的方式,并使类型具有唯一的完全限定名称。在概念上,命名空间和计算机文件系统中的文件夹比较类似。命名空间具有以下4个用途。 组织大型代码项目。 使用.运算符将它们分隔。 using指令不必为每个类指定命名空间的名称。 global命名空间是.NET Framework应用程序的“根”命名空间,global::System始终引用.NET Framework中的System命名空间。
7.2 声明命名空间 namespace关键字用于声明一个范围,并称该范围为命名空间。通过命名空间可以组织程序的源代码,并为源代码提供一个全局唯一类型访问的方法。声明命名空间的具体语法如下。 namespace qualified-identifier { body [;] } qualified-identifier表示命名空间的名称,该名称必须唯一,body表示该命名空间的内容主体(该部分是不可缺少的),;(分号)是一个可选项。一旦声明了一个命名空间之后,该命名空间中的主体源代码将在该命名空间中进行编译。
7.3 .(点号)运算符 .(点号)运算符用于成员访问。在命名空间中,.(点号)运算符指定命名空间的成员。【示例7-7】使用.(点号)运算符访问了System命名空间下的Int32类型,并声明了该类型的i变量。 System.Int32 i;
7.4 ::(双冒号)运算符 ::(双冒号)运算符用于在指定命名空间中查找标识符,它通常放置在两个标识符之间。【示例7-10】使用::(双冒号)运算符在global命名空间中查找System.Console类,并调用WriteLine()方法在控制台上显示“This is a string.”字符串。 global::System.Console.WriteLine("This is a string."); 注意:global表示在全局命名空间中的查找,而不是在个别特定的命名空间中查找。
7.5 using指令 using关键字存在两种常用用法:作为指令和作为语句。当using关键字作为指令时,它用于为命名空间或类型创建别名或导入其他命名空间中定义的类型。当using关键字作为语句时,它用于定义一个范围,并在此范围的末尾将释放对象。本节介绍using关键字作为指令的详细用法。
7.5.1 创建命名空间或类型别名 using指令可以为一个命名空间或类型创建特定的、简单的别名,使得通过该别名也可以引用该命名空间或类型。具体语法如下: using old-identifier = new- identifier; old-identifier表示命名空间或类型的旧名称,new- identifier表示该命名空间或类型的新名称,即别名。
7.5.2 导入命名空间 using指令还可以将一个命名空间中所包含的类型导入到指定的程序体或文件中,从而该程序体或文件中的代码可以直接访问该命名空间中的类型,而不需要加上类型的完全限定符(如命名空间的名称)。具体语法如下: using identifier; identifier表示被导入的命名空间。
7.6 .NET Framework常用命名空间 Microsoft .NET Framework类库(Class Library)是一个综合性的面向对象的可重用类型集合,由.NET Framework SDK中的类、接口、值类型等组成的库。.NET Framework类库是创建.NET Framework应用程序、组件和控件的基础,并为开发人员提供了大量的命名空间、类等基础技术。
7.7 小结 本章主要介绍了C#语言中的命名空间,如声明命名空间、.(点号)运算符、::(双冒号)运算符、using指令、.NET Framework常用命名空间等。其中,读者要着重掌握声明命名空间、using指令和.NET Framework常用命名空间,为后续编写C#程序代码奠定基础。下一章将要介绍C#语言中的类。
7.8 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_07”的控制台应用程序,并实现以下功能。 7.8 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_07”的控制台应用程序,并实现以下功能。 (1)将名称为“class1.cs”的文件添加到该应用程序中。 (2)设置class1.cs文件的命名空间为“MyTest_07_01”。 (3)将名称为“class2.cs”的文件添加到该应用程序中。 (4)设置class2.cs文件的命名空间为“MyTest_07_02”。
第8章 类 C#是面向对象的编程语言,它使用类和结构来实现类型(如Windows窗体、ASP.NET Web窗体、用户界面控件等)。典型的C#应用程序由程序员定义的类和.NET Framework的类组成。本章将讲解C#语言中的类,主要介绍以下知识点。 类概述; 类数据成员; 类函数成员 创建派生类; 展示类的多态性。
8.1 类概述 类(class)是一种数据结构,它可以包含数据成员(常量和字段)、函数成员(方法、属性、事件、索引器、运算符、实例构造函数、静态构造函数和析构函数)以及嵌套类型。类类型支持继承,继承是一种机制,它使派生类可以对基类进行扩展和专用化。
8.1.1 类声明 声明类需要使用class关键字,语法如下。 8.1.1 类声明 声明类需要使用class关键字,语法如下。 class-modifiers class identifier class-base class-body ; class-modifiers表示类修饰符(可选),identifier表示类的名称,class-base表示类的基类或接口等(可选),class-body表示类体,;(分号)是可选的。
8.1.2 类修饰符 类修饰符放在class关键字的前面,它包括new、public、protected、internal、private、abstract和sealed共7个关键字。其中,public、protected、internal和private修饰符控制类的可访问性。它们的意义具体说明如下。 public修饰符表示该类是公开的,访问不受限制。 protected修饰符表示该类只能是本身或其派生的类访问。 internal修饰符表示该类只能是在当前应用程序中访问。 private修饰符表示该类只能是本身访问。
8.1.3 类继承 类类型支持继承(inherit),继承是一种机制,它使派生类可以对基类进行扩展和专用化。在类声明语法中,class-base表示类的基类或接口等(可选),即一个类可以从另外一个类继承而来。
8.1.4 类、对象和实例化 类是一种数据结构,它为动态创建类的实例提供了定义。类的实例又称为对象。实例化是一种操作,它可以为类的实例分配内存。
8.2 类成员 类可以包含多种成员,如常量、字段、方法等,具体说明如下。 (1)常量 (2)字段 (3)方法 (4)属性 8.2 类成员 类可以包含多种成员,如常量、字段、方法等,具体说明如下。 (1)常量 (2)字段 (3)方法 (4)属性 (5)事件 (6)索引器 (7)运算符 (8)实例构造函数 (9)析构函数 (10)静态构造函数 (11)类型 上述成员除了类型之外,可以分类两大类:数据成员和函数成员。其中,数据成员包括常量和字段;函数成员包括方法、属性、事件、索引器、运算符、实例构造函数、析构函数和该类的静态构造函数。本节将详细介绍上述类的成员。
8.2.1 常量 常量(constant)用来表示常数值,它的值在编译时计算。常量的类型必须为sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal、bool、string、枚举类型或引用类型。 在声明常量时,需要使用const关键字。
8.2.2 字段 字段(field)是类中最为常见的数据成员,它为类中的变量。如果在同一个语句中同时声明多个字段,那么字段之间需要使用,(逗号)分隔。根据字段的修饰方式,可以把字段分为以下4种。 静态字段,使用static修饰,对应于静态变量。 实例字段,不使用static修饰,对应于实例变量。 只读字段,使用readonly修饰。 易失字段,使用volatile修饰。该类型的字段很少使用,在此不做详细介绍。
8.2.3 方法 方法(method)是包含一系列语句的代码块,通过这些代码块能够实现预先定义的计算或操作。方法一般声明在类或结构中,由访问级别、返回值、方法名称、方法参数和方法体组成。其中,访问级别、返回值、方法名称和方法参数统称为方法的“签名”。方法参数包括在小括弧(“()”)中,多个参数使用,(逗号)分隔。如果为空括号,则表示该方法不需要参数。 1.方法参数 2.静态方法和实例方法 3.虚方法和重写方法 4.密封方法 5.抽象方法
8.2.4 属性 属性(property)是C#语言所特有的一种机制,它可以用于访问对象或类的特性的成员。属性和字段非常相似,而且访问属性和字段的语法相同。但是,属性不表示存储位置(字段表示一个存储位置)。 属性通过一种被称为访问器的机制来获取或修改其值。其中,获取属性的值的访问器为称为get访问器,修改属性的值的访问器被称为set访问器,它们的具体说明如下: get访问器相当于一个无参数方法,且该访问的返回值的类型和属性的类型相同。在get访问器中,必须包含return语句,返回该属性的值。 set访问器相当于一个返回类型为void的方法,且该方法只有一个参数,参数的类型和属性的类型相同。特别地,该方法的参数名称始终约定为value。
8.2.5 索引器 索引器(indexer)其实是一种含有参数的属性,又称为含参属性。它提供索引的方式来访问对象,即与数组的访问方式相同。声明索引器时,需要使用this关键字。
8.2.6 构造函数 构造函数是类的一种特定的方法,它的名称和其所属类的名称相同。构造函数是在创建给定类型的对象时执行的类方法,通常用来初始化新对象的数据成员,即设置数据成员的默认值。在任何时候,只要创建类,就会调用它的构造函数。如果开发人员没有为类显式提供构造函数,则默认情鱿C#编译器将为该类创建一个默认的构造函数 1.实例构造函数 2.静态构造函数
8.2.7 析构函数 析构函数(destructor)是一种用于实现销毁类实例所需操作的成员。它和类的构造函数恰恰相反,类的构造函数用来初始化该类的实例,而析构函数用来释放该类的实例占用的资源,并销毁该类的实例。 析构函数的名称和类的名称一样,并带有“~”字符。
8.2.8 事件 事件(event)是一种使对象或类能够提供通知的成员。客户端可以通过提供事件处理程序(event handler)为相应的事件添加可执行代码。类或对象可以通过事件向其他类或对象通知发生的相关事情。 一个类或对象可以事先向其他类或对象注册一个事件,然后在一定的时候引发该事件。如开发人员可以向在Windows窗体中的按钮注册一个事件,当用户单击该按钮时,将引发该已注册的事件。有关事件的知识点将在第12章中详细介绍。
8.3 实例一:使用类的继承特性 本实例创建了3个类:Person、Teacher和Student。Teacher和Student类都继承与Person类,它们的继承关系如图8.1所示。
8.3.1 设计Person类 Person类包含3个字段:name、age和courses。其中,name字段表示姓名,类型为string;age字段表示年龄,类型为int;courses字段表示课程列表,它为一个元素类型为string的数组。
8.3.2 设计Teacher类 Teacher类继承于Person类,且还包含1个字段:duty。该字段表示职务,类型为string。
8.3.3 设计Student类 Student类继承于Person类,且还包含1个字段:className。该字段表示班级,类型为string。
8.3.4 测试Person、Teacher和Student类
8.4 小结 本章主要介绍了C#语言中的类,如类概述、类数据成员、类函数成员、派生类、多态性等。其中,读者要着重掌握类的数据成员和函数成员,以及使用类的派生和多态性来创建派生类的方法,为后续编写C#程序代码奠定基础。下一章将要介绍C#语言中的结构。
8.5 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_08”的控制台应用程序,并实现以下功能。 8.5 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_08”的控制台应用程序,并实现以下功能。 (1)将名称为“class1.cs”的文件添加到该应用程序中。 (2)创建一个名称为“MyClass”的类,并在该类中定义如下成员。 sum常量; value字段; GetValue()方法; Index属性; 只包含一个类型为int的参数、且返回类型为string的索引器; printHandler事件。
第9章 结构 结构和类非常相似。和类相比,结构更加适合用于表示轻量级对象(如复数、坐标、矩阵、颜色等)。通过结构,只要使用少量数据成员,就能够表示这些轻量级对象,从而简化了应用程序。本章将讲解C#语言中的结构,主要介绍以下知识点。 结构概述; 结构成员; 结构和类的区别 创建Point结构; 创建Complex结构。
9.1 结构概述 结构(struct)与类非常相似,它们都表示可以包含数据成员(常量和字段)和函数成员(方法、属性、事件、索引器、运算符、实例构造函数和静态构造函数)的数据结构。但是,结构是一种值类型,结构类型的变量直接包含了该结构的数据。类类型是一种引用类型,类类型的变量仅仅包含访问某个数据的一个引用(或地罚 1.结构声明 2.结构修饰符
9.2 结构成员 结构和类一样,它也包含多种成员,如常量、字段、方法等,具体说明如下。 常量 字段 方法 属性 事件 索引器 运算符 9.2 结构成员 结构和类一样,它也包含多种成员,如常量、字段、方法等,具体说明如下。 常量 字段 方法 属性 事件 索引器 运算符 实例构造函数 静态构造函数 类型 上述成员除了类型之外,可以分类两大类:数据成员和函数成员。其中,数据成员包括常量和字段;函数成员包括方法、属性、事件、索引器、运算符、实例构造函数和静态构造函数。
9.3 结构和类的区别 结构和类虽然比较相似,但是还存在以下8个方面的区别。 9.3 结构和类的区别 结构和类虽然比较相似,但是还存在以下8个方面的区别。 结构是值类型,并隐式地从类System.ValueType继承,而类是引用类型,并从类object继承。 结构总是分配在堆栈上,而类常常分配在堆上。如果对结构类型的变量进行赋值,那么将创建所赋的值的一个副本。 结构类型字段的默认值是字段本身的类型的默认值,而类类型字段的默认值为null。因此,结构是存在默认值的。 结构不能声明无参数的实例构造函数。 结构不能声明析构函数。 在结构中,初始化实例字段是错误的。 对于结构而言,不像类那样存在继承。一个结构不能从另一个结构或类继承,而且不能作为一个类的基。但是,结构从基类Object继承。结构可实现接口,其方式同类完全一样。 实例化结构时,可以不使用new运算符,而且结构对象的字段具有默认初始值。而实例化类时,必须使用new运算符,并需要设置各个字段的初始值。
9.3.1 继承 结构不支持继承。因此,在声明结构成员时,不能使用protected或protected internal修饰符。结构类型永远不会是抽象的,并且始终是隐式密封的。因此,结构不能作为其他结构或类的基结构,而且在声明结构时,不能使用abstract或sealed修饰符。
9.3.2 this保留字 this是一个保留字,它只能在实例构造函数、实例方法或实例访问器的块中使用,且表示当前实例。在类中,this表示当前实例,它的值不能被修改。在结构中,this相当于一个变量。如果在结构的实例构造函数中,this相当于一个结构类型的out参数;如果在结构的实例函数成员中,this相当于一个结构类型的ref参数。
9.3.3 构造函数 在结构中,不能声明无参数的实例构造函数。其实,每一个结构都隐式地具有一个无参数实例构造函数,该构造函数将初始化该结构所有字段的值。如果字段的类型为值类型,则将该字段的值设置为其类型的默认值。如果字段的类型为引用类型,则将该字段的值设置为null。 另外,结构还可以声明带有参数的实例构造函数。
9.4 实例一:创建坐标点结构Point 本实例创建一个名称为Point的结构,用来表示二维坐标值。该结构包含2个属性:X和Y,它们分别表示X坐标值和Y坐标值。
9.4.1 设计Point结构 Point结构包含2个字段:x和y。其中,x字段表示X坐标的值,y字段表示Y坐标的值,它们的类型都为int。
9.4.2 测试Point结构 【实例9-1】测试了Point结构,并使用该结构创建一个实例p,然后显示该实例的X坐标和Y坐标的值。
9.5 实例二:创建复数结构Complex 本实例创建一个名称为Complex的结构,用来表示一个复数。该结构包含2个属性:Integer和Fraction,它们分别表示复数的整数部分和小数部分。另外,该结构重载了+运算符,并使用该运算符计算了两个复数的和。
9.5.1 设计Complex结构 Complex结构包含2个字段:integer和fraction。其中,integer字段表示复数的整数部分,fraction字段表示复数的小数部分,它们的类型都为int。
9.5.2 测试Complex结构 【实例9-2】测试了Complex结构,并使用该结构创建两个实例lc和rc,然后计算这两个实例的和,并显示计算结果。
9.6 小结 本章主要介绍了C#语言中的结构,如结构概述、结构成员、结构和类的区别、Point结构、Complex结构等。其中,读者要着重掌握结构的成员,以及创建结构的方法,为后续编写C#程序代码奠定基础。下一章将要介绍C#语言中的数组。
9.7 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_09”的控制台应用程序,并实现以下功能。 9.7 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_09”的控制台应用程序,并实现以下功能。 (1)将名称为“class1.cs”的文件添加到该应用程序中。 (2)创建一个名称为“MyStruct”的类,并在该类中定义如下成员。 sum常量; value字段; GetValue()方法; Index属性; 只包含一个类型为int的参数、且返回类型为string的索引器; printHandler事件。
第10章 数组 数组可以将多个类型相同的元素组合为一个整体,从而通过数组统一访问或操作这些元素。数组是C#语言最常用的数据结构之一。它是相同数据类型的对象的集合。该集合的长度(即数组的长度)可以为0或大于0的整数。本章将讲解使用数组进行编程的方法,主要介绍以下知识点。 数组概述; 数组分类; 静态数组; 动态数组; 抽签程序。
10.1 数组概述 数组是一个有序的数据集合。数组中的每一个元素的数据类型都相同。元素的数据类型被称为元素类型,它可以为任何类型,甚至可以为数组。数组可以用一个统一的数组名和下标来唯一确定组中的元素。例如,一个班有50名学生,可以用s1、s2、s3、…、s50表示50个学生的成绩。s为数组名,下标表示学生的序号。s10(整数10为下标)表示第10个学生的成绩。
10.1.1 数组的维度数 大家都知道,直线由点构成,平面由直线构成、空间由平面构成。如果要描述直线上的一个点,则只需要一个值。如果要描述平面上的一个点,则需要两个值。如果要描述空间中的一个点,则需要3个值。在直线、平面和空间中,称描述一个点所需要值的数量为“维度数”。 数组也一样,它也存在维度数的概念。当在要描述数组中的一个元素时,如果只需要一个值(数组的下标),那么该数组的维度数为1;如果需要两个值,那么该数组的维度数为2;依次类推。如上述提及的s数组的维度数就是1。根据数组的维度数不同,可以把数组分为以下3种类型 一维数组,维度数为1的数组。 二维数组,维度数为2的数组。 多维数组,维度数大于2的数组。
10.1.2 声明数组 在C#程序设计中,如果需要某一个数组,则必须首先声明该数组。声明一维数组的语法如下所示。 10.1.2 声明数组 在C#程序设计中,如果需要某一个数组,则必须首先声明该数组。声明一维数组的语法如下所示。 type[] arrayName; 其中,type表示数组元素的类型,如int、double、string、object等;arrayName表示数组的名称。
10.1.3 实例化数组 实例化数组就是为数组分配相应的内存。注意,声明一个数组,并不为该数组分配相应的内存。
10.1.4 初始化数组 初始化数组就是初始化数组中每一个元素的值,即为数组中的每一个元素进行赋值。数组被实例化之后,每个元素都为其元素类型的默认值。一般情况下,只有初始化数组之后,该数组才具有实际运算的意义。初始化数组存有多种方法,主要包括以下4种。 1.直接赋值 2.使用“new”操作符,并指定了数组的长度 3.使用“new”操作符,省略数组的长度 4.直接设置数组的每一个元素的值
10.1.5 遍历数组 遍历数组是指依次访问数组中的每一个元素,并执行预先设计的操作。访问数组的元素最常用方法之一就是使用下标(或索引)。根据是否使用下标可以遍历数组方式分为两种。第一种,使用下标遍历,如for、while、do…while等语句。第二种,不使用下标遍历,如foreach语句。 1.使用下标遍历数组 2.不使用下标遍历数组
10.2 数组分类 根据数组的维度数和元素的类型不同,可以把数组分为4种类型:一维数组(维度数为1的数组)、二维数组(维度数为2的数组)、多维数组(维度数大于2的数组)和交错数组(元素的类型为数组的数组)。本小节将介绍声明、实例化和初始化各种不同类型数组的方法。
10.2.1 一维数组 一维数组是指维度数为1的数组,它是最简单的数组,也是最常用的数组。声明一维数组的语法如下所示。 10.2.1 一维数组 一维数组是指维度数为1的数组,它是最简单的数组,也是最常用的数组。声明一维数组的语法如下所示。 type[] arrayName; 其中,type表示数组元素的类型,如int、double、string、object等;arrayName表示数组的名称。
10.2.2 二维数组 二维数组是指维度数为2的数组。声明二维数组的语法如下所示。 type[,] arrayName; 10.2.2 二维数组 二维数组是指维度数为2的数组。声明二维数组的语法如下所示。 type[,] arrayName; 其中,type表示数组元素的类型,如int、double、string、object等;中括号([])中间存在一个逗号(,)表示该数组为一个二维数组;arrayName表示数组的名称。
10.2.3 多维数组 多维数组是指维度数大于2的数组,如三维数组、四维数组等。声明三维数组的语法如下所示。 10.2.3 多维数组 多维数组是指维度数大于2的数组,如三维数组、四维数组等。声明三维数组的语法如下所示。 type[, ,] arrayName; 其中,type表示数组元素的类型,如int、double、string、object等;中括号([])中间存在两个逗号(,)表示该数组为一个三维数组;arrayName表示数组的名称。
10.2.4 交错数组 交错数组又称为“数组的数组”,它的元素也为一个数组。声明二维交错数组的语法如下所示。 10.2.4 交错数组 交错数组又称为“数组的数组”,它的元素也为一个数组。声明二维交错数组的语法如下所示。 type[][] arrayName; 其中,type表示数组元素的类型,如int、double、string、object等;type关键字之后包含两个中括号([])表示该数组为一个二维交错数组;arrayName表示数组的名称。
10.3 静态数组System.Array .NET框架提供了两种数组:静态数组和动态数组。一旦为数组分配内存之后,如果该数组的大小是不能修改的,则称该数组为静态数组;反之,则称之为动态数组。静态数组静态数组由System.Array类实现,动态数组由System.ArrayList类实现。本小节将介绍静态数组的基本属性和方法,以及它们的使用方法。 注意:本章前面小节所介绍的数组都是属于静态数组。
10.3.1 属性 System.Array类包含7个属性,如获取数组长度的Length属性、获取数组秩的Rank等,如表10.1所示。 10.3.1 属性 System.Array类包含7个属性,如获取数组长度的Length属性、获取数组秩的Rank等,如表10.1所示。 属性 描述 Length 数组的长度,即数组所有维度中元素的总数。该值为32位整数。 LongLength 数组的长度,即数组所有维度中元素的总数。该值为64位整数。 Rank 数组的秩,即数组的维度数。 IsFixedSize 表示数组的大小是否固定。 IsReadOnly 表示数组是否为只读。 IsSynchronized 表示是否同步访问数组。 SyncRoot 获取同步访问数组的对象。
10.3.2 方法 System.Array类包含多个方法,如获取数组长度的GetLength()方法、获取指定元素值的GetValue()方法,获取指定元素索引的IndexOf()方法等,如表10.2所示。 属性 描述 GetValue() 获取指定元素的值。 SetValue() 设置指定元素的值。 Clear() 清空数组中的所有元素。 GetLength() 获取指定维的元素数量。该值为32位整数。 GetLongLength() 获取指定维的元素数量。该值为64位整数。 IndexOf() 获取匹配的第一个元素的索引。 LastIndexOf() 获取匹配的最后一个元素的索引。 FindIndex() 搜索指定元素,并获取第一个匹配元素的索引。 FindLastIndex() 搜索指定元素,并获取最后一个匹配元素的索引。 Copy() 将一个数组中的一部分元素复制到另一个数组。 CopyTo() 将一维数组的所有元素复制到另外一个一维数组。 Clone() 复制数组。 ConstrainedCopy() 指定开始位置,并复制一系列元素到另外一个数组中。 Sort() 对一维数组中的元素进行排序。 Reverse() 反转一维数组中元素的顺序。 BinarySearch() 使用二进制搜索算法在一维的排序数组中搜索指定元素。 GetLowerBound() 获取数组中指定维度的下限。 GetUpperBound() 获取数组中指定维度的上限。
10.3.3 获取数组长度 数组长度是指数组元素的总数,即数组每一维度元素数量之乘积。获取数组长度的方法存在多种,可以通过System.Array类的属性获取,也可以通过Array类的方法获取。 1.通过属性获取数组的长度 2.通过方法获取数组的长度
10.3.4 获取元素的值 获取数组中指定元素的值最简单方法就是通过“[]”运算符。
10.3.5 设置元素的值 和获取指定元素的值一样,也存在两种方法设置元素的值。第一种方法就是直接通过数组名和“[]”运算符来设置元素的值。
10.3.6 获取元素的索引 System.Array类为一维数组提供了获取元素的索引的两个静态方法:IndexOf()和LastIndexOf()方法。IndexOf()方法获取匹配的、第一个元素的索引。LastIndexOf()方法获取匹配的、最后一个元素的索引。
10.3.7 排序数组 System.Array类为一维数组提供了一个名称为“Sort()”的方法,该方法可以对一维数组中的元素进行排序。能够使用Sort()方法排序的数组中的元素必须实现IComparable接口,即数组中的元素是能够进行比较的,否则不能对该数组中的元素进行排序。
10.3.8 反转数组 System.Array类为一维数组提供了一个名称为“Reverse()”的方法,该方法可以反转一维数组中的全部元素或部分连续的元素。
10.4 动态数组System.ArrayList 动态数组又称为可变数组,且数组的长度可以动态修改。动态数组由System.ArrayList类实现,它在保存元素时,仅仅保存元素的引用,而不是元素的具体值。因此,动态数组元素的数据类型可以是任何类型,而且各个元素的数据类型也可以不相同。
10.4.1 属性 System.ArrayList类包含了7个属性,如获取数组元素数量的Count属性、指示数组是否为只读的ReadOnly属性等,如表10.3所示。 属性 描述 Capacity 数组的容量。 Count 数组元素的数量。 Item 指定索引处的元素。 IsFixedSize 表示数组的大小是否固定。 IsReadOnly 表示数组是否为只读。 IsSynchronized 表示是否同步访问数组。 SyncRoot 获取同步访问数组的对象。
10.4.2 方法 System.ArrayList类包含了多个方法,如添加新元素到数组末尾中的Add()方法、从数组中删除指定元素的Remove()方法等。
10.4.3 添加元素 向动态数组添加一个新的元素可以使用Add()方法或者Insert()方法。Add()方法可以将新的元素添加到数组的末尾处,Insert()方法可以将新的元素添加到数组的指定位置。如果希望把新的元素插入到数组(元素数量大于0)的开始处,则只能使用Insert()方法。
10.4.4 移除元素 如果要从动态数组中移除元素,则可以使用Remove()、RemoveAt()或RemoveRange()方法。Remove()方法从数组中移除指定的元素,RemoveAt()方法从数组中移除指定位置处的元素,RemoveRange()方法从数组中移除指定范围内的元素。
10.5 实例一:抽签程序 【实例10-1】使用整型数组实现抽签功能。该功能由Draw(int count)函数实现,count参数表示签号的总数量。
10.6 小结 本章主要介绍了C#语言中的数组,如数组概述、数组分类、静态数组、动态数组、抽签程序等。其中,读者要着重掌握数组分类、一维数组、静态数组和动态数组,以及使用数组编程的方法,为后续编写C#程序代码奠定基础。下一章将要介绍C#语言中的接口。
10.7 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_10”的控制台应用程序,并实现以下功能。 10.7 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_10”的控制台应用程序,并实现以下功能。 (1)将名称为“class1.cs”的文件添加到该应用程序中。 (2)创建一个名称为“UsingArray”的类,并在该类中定义如下成员,并使用这些成员测试Array类的各个方法的用途。 名称为“values1”的、元素类型为int的一维数组; 名称为“values2”的、元素类型为string的一维数组; 名称为“values3”的、元素类型为int的二维数组; 名称为“values4”的、元素类型为string的一维数组; 名称为“values5”的、元素类型为int的三维数组; 名称为“values6”的、元素类型为int的交错数组。
第11章 接口 接口和类一样,也是属于引用类型。接口可以用来描述属于类或结构的一组相关功能,即定义一种协议。类或结构可以实现接口,同时必须遵循它们所实现接口定义的协议。本章将讲解C#语言中的接口,主要介绍以下知识点。 接口概述; 接口成员; 实现接口; 抽象类和接口。
11.1 接口概述 接口(interface)定义一种协议,实现该接口的类或结构必须遵循该协议。一个接口可以继承于一个或多个其他接口,一个类或结构也可以实现一个或多个接口。接口可以包含4种成员:方法、属性、事件和索引器。接口本身不提供它所定义的成员的实现,它仅仅指定实现该接口的类或结构必须提供的成员。
11.1.1 接口声明 声明接口需要使用interface关键字,语法如下。 11.1.1 接口声明 声明接口需要使用interface关键字,语法如下。 interface-modifiers interface identifier interface-base interface-body ; interface-modifiers表示接口修饰符(可选),identifier表示接口的名称,interface-base表示接口的基接口(可选),interface-body表示接口体,;(分号)是可选的。4
11.1.2 接口修饰符 接口修饰符一般位于接口声明中的interface关键字之前,共包括5个修饰符:new、public、protected、internal和private。其中,public、protected、internal和private修饰符控制接口的可访问性。它们的意义具体说明如下。 public修饰符,表示该接口是公开的,访问不受限制。 protected修饰符,表示该接口只能是本身或其派生的接口访问。 internal修饰符,表示该接口只能是在当前应用程序中访问。 private修饰符,表示该接口只能是本身访问。
11.1.3 接口继承 接口可以继承于一个或多个其他接口,也可以不继承。被继承的接口称为该接口的显式基接口。当一个接口具有一个或多个显式基接口时,在声明该接口时,接口标识符后就要紧跟一个冒号和一个由,(逗号)分隔的基接口标识符列表。
11.2 接口成员 接口的成员必须是方法、属性、事件或索引器,而不能包括常量、字段、运算符、实例构造函数、析构函数或类型,也不能包含任何种类的静态成员。一个接口可以不包括任何成员,也可以包括一个或多个成员。接口成员默认隐式地具有public访问属性,而且在声明接口成员时不能包含任何修饰符(如abstract、public、protected、internal、private、virtual、override和static),否则会发生编译时错误。 注意:一个接口的成员包括两部分:由接口本身声明的成员和其从基接口继承的成员。
11.2.1 属性 在接口中声明属性时,只能声明该属性具有哪个访问器(如get或set访问器),而不能实现该访问器。接口属性的访问器只用于表明该属性是只读的、只写的还是读写的,访问器体必须始终是一个;(分号)。
11.2.2 索引器 接口索引器和接口属性比较相似。在接口中声明索引器时,只能声明该索引器具有哪个访问器(如get或set访问器),而不能实现该访问器。接口索引器的访问器只用于表明该索引器是只读的、只写的还是读写的,访问器体必须始终是一个;(分号)。
11.2.3 方法 在接口中声明方法时,只能声明该方法的签名,而且该方法的方法体只能为;(分号),而不能包括该方法的实现代码。
11.2.4 事件 在接口中声明事件时,只能声明该事件的签名,而且事件的名称之后必须接一个;(分号)。
11.3 实现接口 类和结构都可以实现接口。如果某一个类或接口实现了一个或多个接口,那么在声明该类或结构时,将实现的接口的标识符包含在该类或结构的基类列表中。
11.3.1 实现属性 实现接口属性即添加该接口属性的实现代码,接口属性的名称和实现该接口属性的名称相同。
11.3.2 实现索引器 实现接口索引器即添加该接口索引器的实现代码。
11.3.3 实现方法 实现接口方法即添加该接口方法的实现代码,接口方法的名称和实现该接口方法的签名相同。
11.3.4 实现事件 实现接口事件即添加该接口事件的实现代码,接口事件的名称和实现该接口事件的签名相同。
11.4 抽象类和接口 抽象类使用abstract修饰符,它用于表示所修饰的类是不完整的,并且它只能用作基类。抽象类与非抽象类在以下3个方面的区别。 抽象类不能直接实例化。如果抽象类使用new运算符,则发生编译时错误。 允许(但不要求)抽象类包含抽象成员。 抽象类不能被密封。 当从抽象类派生非抽象类时,这些非抽象类必须实现所继承的所有抽象成员,即重写这些抽象成员。
11.5 实例一:设计算术计算接口 【实例11-1】设计了用于算术计算的ICompute接口。该接口包括4个方法,具体说明如下。 11.5 实例一:设计算术计算接口 【实例11-1】设计了用于算术计算的ICompute接口。该接口包括4个方法,具体说明如下。 double Add(double leftValue,double rightValue),计算两个数的和。 double Sub(double leftValue,double rightValue),计算两个数的差。 double Multiply(double leftValue,double rightValue),计算两个数的积。 double Div(double leftValue,double rightValue),计算两个数的商。
11.6 小结 本章主要介绍了C#语言中的接口,如接口概述、接口成员、实现接口,抽象类和接口区别等。其中,读者要着重掌握接口成员和实现接口的方法,为后续编写C#程序代码奠定基础。下一章将要介绍C#语言中的委托和事件。
11.7 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_11”的控制台应用程序,并实现以下功能。 11.7 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_11”的控制台应用程序,并实现以下功能。 (1)将名称为“class1.cs”的文件添加到该应用程序中。 (2)创建一个名称为“MyInterface”的接口,并在该接口中定义属性、索引器、方法、事件等成员。
第12章 委托和事件 委托是C#语言中一种引用方法的类型,和C++中处理函数指针的情况比较相似。不但可以向委托实例注册方法列表,而且还可以通过委托实例来调用方法列表中的方法。事件是一种特殊的委托,它包含两个参数:指示事件源的“对象源”参数和封装事件的其他任何相关信息的“e”参数。本章将讲解C#语言中的委托和事件,主要介绍以下知识点。 声明委托; 委托实例化; 委托调用; 声明事件; 注册事件和移除事件; 调用事件。
12.1 委托 熟悉C++中函数指针的读者可能比较容易理解委托。委托(delegate)是一种数据结构,它是用来处理类似于C++中函数指针的情况,即委托能够引用静态方法或引用类实例及其实例方法。特别地,委托是完全面向对象的,同时也封装了对象实例和方法。 所有委托类型的基类是System.Delegate类。System.Delegate类本身不是委托类型,而且不允许显式地直接从该来派生新的类型。委托实例封装了一个调用列表,该列表包含了一个或多个方法,每个方法称为一个可调用实体。
12.1.1 委托声明 委托类型的声明将创建一个协定,该协定指定一个或多个方法的签名。委托是委托类型的实例,它可以引用静态方法或者实例方法。声明委托需要使用delegate关键字,语法如下。 delegate-modifiers delegate return-type identifier delegate-modifiers表示委托的修饰符(可选),它包括new、public、protected、internal和private共5个关键字。其中,public、protected、internal和private修饰符控制委托的可访问性。它们的意义具体说明如下。 public修饰符,表示该委托是公开的,访问不受限制。 protected修饰符,表示该委托只能是本身委托访问。 internal修饰符,表示该委托只能是在当前应用程序中访问。 private修饰符,表示该委托只能是本身访问。
12.1.2 创建向委托注册方法 一旦声明一个委托之后,那么就指定了该委托方法列表中的方法签名,包括方法列表中的方法的返回类型和方法参数。如果一个方法能够注册到某一个委托中,那个该方法的签名必须与该委托的所指定的签名完全匹配。匹配规则如下。 方法的返回类型必须和委托的返回类型相同。 方法的方法参数必须和委托的方法参数相同,参数的具体名称可以不相同。
12.1.3 委托实例化 委托实例化可以创建委托类型的实例,并向该实例注册方法列表。委托类型的实例的方法列表可以为静态方法、实例方法或者另外一个委托实例。 注意:委托实例化,它把静态方法、实例方法或者另外一个委托的名称作为该实例的方法参数进行传递。
12.1.4 委托的方法列表 一个委托实例都必须包含其方法列表,方法列表可以包含一个或多个方法。委托实例除了在其实例化时注册方法之外,还可以通过“+”或“+=”运算符向该实例的方法列表中的注册方法,通过“-”或“-=”运算符向该实例的方法列表中的移除方法
12.1.5 委托调用 一个委托实例的方法列表,又称为该委托实例的调用列表。一个调用列表可能包含一个或多个方法。如果一个调用列表包含多个方法时,当该委托实例被调用时,它将按照调用列表中方法的注册顺序依次调用每一个方法。
12.2 事件 事件(event)是一种使对象或类能够提供通知的成员。客户端可以通过提供事件处理程序为相应的事件添加可执行代码。客户端可以实现为事件定义一些操作或方法,当事件发生时,将调用该事件事先定义的操作或方法。
12.2.1 声明事件 事件其实是一种特殊类型的委托,它包含两个参数:指示事件源的“对象源”参数和封装事件的其他任何相关信息的“e”参数。其中,“e”参数的类型为System.EventArgs类型或从System.EventArgs类派生的类型。声明事件一般包括以下两个步骤。 (1)声明事件的委托。 (2)声明事件本身。
12.2.2 注册事件 一个事件一旦声明之后,该事件的默认值为null。如果希望该事件执行事先指定的操作,则首先向该事件注册方法列表(即委托的调用列表)。注册事件可以使用“+=”运算符。
12.2.3 移除事件 除了注册事件之外,还可以移除事件。移除事件使用“-=”运算符。
12.2.4 调用事件 声明一个事件之后,如果没有向该事件注册方法,那么该事件的值为空(null)。因此,在调用事件时,往往需要检查该事件是否为空。
12.3 实例一:测试打印事件 【实例12-1】演示了测试打印事件的方法。该功能由TestPrintEvent类和PrintEventHandler委托实现。
12.4 小结 本章主要介绍了C#语言中的委托和事件,如声明委托、委托实例化、委托调用、声明事件、注册事件、移除事件、调用事件等。其中,读者要着重掌握声明委托、委托调用、声明事件、注册事件和调用事件,为后续编写C#程序代码奠定基础。下一章将要介绍C#语言中的异常处理。
12.5 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_12”的控制台应用程序,并实现以下功能。 12.5 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_12”的控制台应用程序,并实现以下功能。 (1)将名称为“class1.cs”的文件添加到该应用程序中。 (2)创建一个名称为“PrintEventHandler”的委托,并使用该委托定义名称为“PrintEvent”的事件,然后测试该事件的使用方法。
第13章 异常处理 异常是程序执行时遇到的任何错误情况或意外行为。应用程序必须能够统一处理在执行期间发生的错误。.NET Framework公共语言运行库提供了一个模型,以统一的方式通知程序发生的错误。本章将讲解C#语言中的异常处理机制,主要介绍以下知识点。 异常概述; try语句; System.Exception类; .NET Framework常用异常类; 创建自定义异常类。
13.1 异常概述 和C++程序语言一样,C#程序语言也存在异常处理机制。C#程序语言中的异常用于处理系统级和应用程序级的错误状态,它是一种结构化的、统一的和类型安全的处理机制。
13.1.1 导致异常的原因 在应用程序运行时,发生异常的原因是多种多样的,如除数为0、堆栈溢出等。导致异常的原因可以归纳为以下2大类。 13.1.1 导致异常的原因 在应用程序运行时,发生异常的原因是多种多样的,如除数为0、堆栈溢出等。导致异常的原因可以归纳为以下2大类。 在执行语句和表达式(C#语言)的过程中,有时会出现一些例外情况,从而使得某些操作无法正常完成,此时就会引发一个异常。 应用程序使用throw语句特意产生一个异常,此时将引发一个异常。
13.1.2 try语句 try语句可以用来捕捉在代码块的执行期间发生的各种异常。它可以包含try块、catch块和finally块,具体说明如下。 try块,一般包含有可能发生异常的代码。 catch块,包含出现异常时需要执行的响应代码。 finally块,包含出现异常时一定执行的代码,如资源清理等操作。
13.1.3 异常处理 异常是由try语句处理的。当发生异常时,系统将搜索与当前try块相关的最近的、可以处理该异常的catch块,然后由该catch块处理该异常。如果与当前try块相关的所有catch块都不能处理该异常,则沿着堆栈向上搜索封闭该异常代码的try块及其相关联的catch块,如果找到,则由该catch块处理该异常。如果还没有找到catch块,则重复上述过程,直到找到catch块。如果到达调用堆栈顶部仍然没有找到处理该异常的catch块,则由默认的异常处理程序处理该异常,然后应用程序终止。
13.2 System.Exception类 System.Exception类表示在应用程序执行期间发生的错误,它是.NET Framework中所有异常的基类型。当系统或应用程序发生错误时,将通过引发包含错误信息的异常来报告错误。一旦异常发生后,将由该应用程序或默认异常处理程序(如System.Exception类)来处理异常。 System.Exception类包含描述错误的可读文本。当异常发生时,应用程序的运行库(如.NET Framework)将产生消息(保存在Exception类的实例的Message属性中)通知用户错误的性质并提供解决该问题的操作建议。Exception类包括以下两类异常。 从SystemException派生的预定义公共语言运行库异常类。 从ApplicationException派生的用户定义的应用程序异常类。
13.3 常用异常类 .NET Framework提供了10个常用异常类,如处理空(null)引用的System.NullReferenceException类、处理数组索引小于0或超过其下标的System.IndexOutOfRangeException类等。这些常用异常类及其说明如表13.3所示。 类 描述 System.NullReferenceException 如果使用null引用,引发此异常。 System.IndexOutOfRangeException 如果使用小于零或超出数组界限的下标访问数组时,引发该异常。 System.InvalidCastException 如果显式转换失败时,就会引发此异常。 System.DivideByZeroException 当除数为0时,引发该异常。 System.StackOverflowException 当堆栈溢出(如无限递归)时,引发该异常。 System.OverflowException 在checked上下文中的算术运算溢出时,引发该异常。 System.OutOfMemoryException 在通过new操作分配内存失败时,引发该异常。 System.ArithmeticException 在算术运算期间发生错误时,引发该异常。 System.TypeInitializationException 静态构造函数引发异常,且没有可以捕捉到它的catch子句时,引发该异常。 System.ArrayTypeMismatchException 如果被存储的元素的实际类型与数组的元素类型不兼容时,引发此异常。
13.4 实例一:自定义异常处理类 本实例创建了一个自定义异常处理类,它的名称为CustomException,并直接继承于System.Exception类。CustomException类声明了一个名称为ErrorCode的属性,表示错误代码。因此,使用CustomException类处理异常,可以为异常添加错误代码。
13.4.1 设计CustomException类 CustomException类包含1个字段:errorCode,表示错误代码,类型为int。程序代码如下。 public class CustomException:System.Exception { private int errorCode = 10001;
13.4.2 使用CustomException类处理异常 【实例13-1】使用CustomException类处理异常,并介绍了使用CustomException类产生异常并捕获该类产生异常的方法。
13.5 小结 本章主要介绍了C#语言中的异常,如异常概述、try语句、System.Exception类、.NET Framework常用异常类、自定义异常类等。其中,读者要着重掌握try语句,以及处理异常的方法,为后续编写C#程序代码奠定基础。下一章将要介绍C#语言中的泛型。
13.6 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_13”的控制台应用程序,并实现以下功能。 13.6 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_13”的控制台应用程序,并实现以下功能。 (1)将名称为“class1.cs”的文件添加到该应用程序中。 (2)创建一个名称为“MyException”的类(继承于Exception),并使用该类处理自定义的异常。
第14章 泛型 泛型(Generic)是具有占位符(类型参数)的类、结构、接口和方法,这些占位符是类、结构、接口和方法所存储或使用的一个或多个类型的占位符。泛型集合类可以将类型参数用作它所存储的对象的类型的占位符;类型参数作为其字段的类型和其方法的参数类型出现。泛型方法可以将其类型参数用作其返回值的类型或者其形参的类型之一。本章将讲解C#语言中的泛型,主要介绍以下知识点 。 泛型概述; 泛型方法; 创建泛型列表 创建泛型堆栈。
14.1 泛型概述 使用过C++模板的读者可能熟悉泛型(Generic)这一概念。C#中的泛型能够将类型作为参数来传递,即在创建类型时,事先使用一个特定的符号(如T等)代替实际的类型,在创建该类型的实例时,才指定T的实际类型。 泛型可以让类、结构、接口、委托和方法按它们存储和操作的数据的类型进行参数化。泛型能提供更强的编译时类型检查,减少数据类型之间的显式转换,以及装箱操作和运行时的类型检查。 使用泛型类型可以最大限度地重用代码、保护类型的安全以及提高性能。泛型最常见的用途是创建集合类。.NET Framework类库在System.Collections.Generic命名空间中包含多个新的泛型集合类,如List<T>、Stack<T>、Queue<T>等。当然,开发人员也可以创建自定义泛型类型。
14.1.1 泛型类声明 泛型类声明也是一种类的声明,因此,泛型类声明也遵循类声明的规则。一个泛型类一般至少包含一个类型形参(14.1.2小节中介绍)。当创建该泛型类的实例时,需要指定该类型形参的具体类型。
14.1.2 类型形参 类型形参放置在类名后,并在“<”和“>”分隔符中指定。类型形参仅仅是一个简单标识符,是将来提供的类型的形式占位符。换句话说,T类型形参只起占位符的作用,直到在使用时才为其指定了实际类型。 每一个类型形参所代表的实际类型由其所在实例创建时指定。特别地,该实例将存储类型形参的数据而不进行数据类型转换。
14.1.3 类型形参的约束 通常地,类型形参的类型可以指定为任何类型。然而,一些类型形参需要指定一定种类的类型,如结构、类等。为了实现该功能,就需要限制类型形参的类型,这种限制被称为约束。即在定义泛型类时,可以限制在实例化类时用于类型参数的类型种类。如果尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误。
14.1.4 泛型类的成员 泛型类的所有成员都可以直接使用其所属类的类型形参。在运行时,类型形参都被替换为相应的实际类型(该类型在创建类的实例时指定)。
14.1.5 泛型类的静态字段 在泛型类中,静态字段的共享方法比较特殊,即只有在具有相同类型形参的类型的实例才能够共享同一个静态字段的值。
14.2 泛型方法 泛型方法(Generic Method)是使用类型参数声明的方法,它可以声明在类、结构或接口中,而这些类、结构或接口本身可以是泛型或非泛型的。如果这些类、结构或接口也是泛型类型时,那么在这些方法内既可以引用该泛型方法的类型形参,也可以使用这些类、结构或接口的类型形参。
14.2.1 声明泛型方法 和普通方法相比,除了普通的参数之外,泛型方法还必须包含类型形参,即泛型方法是指在声明中包含类型形参的方法。
14.2.2 调用泛型方法 泛型方法调用可以显式指定类型实参列表,或者可以省略类型实参列表并依赖类型推断确定类型实参。通常地,调用泛型方法和调用普通方法一样,但需要为类型形参提供相应的类型实参列表。
14.2.3 通过委托调用泛型方法 除了14.3.2中调用泛型方法的方法之外,还可以通过委托来调用泛型方法。
14.2.4 虚泛型方法 和普通方法一样,泛型方法也存在虚泛型方法,它也可以使用abstract、virtual和override修饰符进行声明。
14.3 实例一:实现泛型列表 本实例首先创建了名称为“GenericList<T>”的泛型类(保存在GenericList.cs文件中),并为该类提供5个方法:Add(T item)、Remove(T item)、RemoveAt(int index)、Clear()和Sort(IComparer<T> c);然后创建该类的实例list,并介绍了GenericList<T>类的属性和方法的使用方法。
14.3.1 设计泛型列表类GenericList<T> GenericList<T>泛型类为T类型形参添加了约束“where T:IComparable”,即约束T类型形参的类型必须实现IComparable接口。GenericList<T>泛型类包含list字段,表示一个列表,类型为List<T>。程序代码如下。 public class GenericList<T> where T:IComparable { /// <summary> 私有字段list,类型为List<T> </summary> private List<T> list;
14.3.2 测试泛型列表 【实例14-1】测试GenericList<T>类,并创建了该类的实例list。
14.4 实例二:实现泛型堆栈 本实例首先创建了名称为“GenericStack<T>”的泛型类(保存在GenericStack.cs文件中),并为该类提供5个方法:IsEmpty()、Push(T item)、Pop()、Peek()和Clear();然后创建该类的实例stack,并介绍了GenericStack<T>类的属性和方法的使用方法。
14.4.1 设计泛型堆栈类GenericStack<T> GenericStack<T>泛型类为T类型形参添加了约束“where T:class”,即约束T类型形参的类型必须为引用类型。GenericStack<T>泛型类包含stack字段,表示一个堆栈,类型为Stack<T>。
14.4.2 测试泛型堆栈 【实例14-2】测试GenericStack<T>类,并创建了该类的实例stack。
14.5 小结 本章主要介绍了C#语言中的泛型,如泛型概述、泛型方法、泛型列表、泛型堆栈等。其中,读者要着重掌握泛型概述,以及创建泛型类(如泛型列表、泛型堆栈等)的方法,为后续编写C#程序代码奠定基础。下一章将要介绍C#语言中的分部类型和可空类型。
14.6 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_14”的控制台应用程序,并实现以下功能。 14.6 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_14”的控制台应用程序,并实现以下功能。 (1)将名称为“class1.cs”的文件添加到该应用程序中。 (2)创建一个名称为“MyGenericStack”的泛型堆栈,同时实现堆栈的常用操作,如入栈、出栈、堆栈是否为空等。
第15章 分部类型和可空类型 分部类型可以将类、结构、接口或者方法的定义拆分为一个或多个部分,甚至可以保存为多个源文件中。可空类型可以用来处理值类型的值为空的情况,它能够指示可空类型的实例是否包含一个确定的值。本章将讲解C#语言中的分部类型和可空类型,主要介绍以下知识点。 声明分部类、结构和接口; 分部类型同名成员处理; 处理分部类型的基接口; 可空类型的属性; 可空类型的方法; bool?类型。
15.1 分部类型 分部类型(Partial type)允许将类、结构和接口划分为多个部分,并存储在不同的源文件中,以便于开发和维护。在Visual Studio 2008集成开发环境中开发应用程序时,有时一个类(如Windows窗体、ASP.NET窗体页等)的一部分代码由机器自动生成,另外一部分代码由程序员编写。如果把这个类设置为分部类,那么这两部分代码可以保存在不同的源文件中,从而增加了应用程序的代码的灵活性。 在声明分部类型的每一个部分时,每一个部分都必须包含partial修饰符,并且分部类型的所有声明代码都必须位于同一命名空间中。partial修饰符表示它所在的类型可能还包含其他部分,但是其他部分并不一定是必须的。如果一个类型只包含一个部分,在声明该类型时使用了partial修饰符,也是正确的。
15.1.1 声明分部类 使用partial修饰符可以用来声明分部类。
15.1.2 声明分部结构 使用partial修饰符可以用来声明分部结构。
15.1.3 声明分部接口 使用partial修饰符除了可以用来声明分部类和结构之外,还可以用来声明接口。
15.1.4 同名成员处理 如果一个分部类型包含了多个部分,那么该类型的所有成员为各个部分成员的并集,并且在每一个部分中可以访问其他部分的成员,即使在声明该成员时使用了private修饰符。然而,在不同部分中声明了同一个名称的成员,则发生编译时错误。除非该成员使用了partial修饰符。
15.1.5 处理基接口 如果一个分部类型包含了多个部分,那么该类型的所有基接口集是每一个部分指定的基接口的并集。一个基接口在分部类型的一个部分中只能指定一次,但是可以在多个部分中同时被指定,即多个部分可以同时指定同一个基接口。 注意:在整个分部类型中,一个基接口的成员的实现只能是一个。但是,一个部分的基接口可以由另外一个部分提供该基接口的实现。
15.2 可空类型 可空类型(Nullable)是一个组合了基础类型的值和布尔空值指示符的结构。可空类型除了表示基础类型的所有值之外,还可以表示空值(null)。可空类型为值类型,声明可空类型存在以下两种形式。 (1)使用System.Nullable类声明可空类型 (2)使用?(问号)声明可空类型
15.2.1 HasValue和Value属性 任何可空类型的实例都包含两个公共只读属性:HasValue和Value。它们的具体意义说明如下。 HasValue属性的类型为bool,它表示该实例是否包含一个确定值。如果HasValue属性的值为true,则表示该实例包含一个确定的值。否则,表示该实例为空,即它不包含确定的值。此时,如果要获取该实例的值,则发生运行时错误。 Value属性的类型为该可空类型的基础类型,它表示该实例的一个确定的值,并作为该实例的值。
15.2.2 GetValueOrDefault()方法 (1)public T GetValueOrDefault() (2)public T GetValueOrDefault(T defaultValue) T表示可空类型的基础类型。如果可空类型的实例的HasValue属性的值为true,则该方法返回该实例的值(即Value属性的值)。如果可空类型的实例的HasValue属性的值为false,(1)方法返回该实例的默认值,(2)方法返回defaultValue参数的值。
15.2.3 bool?类型 bool?类型为可空布尔类型,它可以表示3个值:true、false和null。可空布尔类型提供了两个运算符:&和|。&运算符表示逻辑与,|运算符表示逻辑或。可空布尔类型的实例运算结果如表15.1所示。 X Y X & Y X | Y true false null
15.3 实例一:测试可空类型 【实例15-1】演示了测试基类型为int的可空类型的方法。该功能由TestNullableType类实现。
15.4 小结 本章主要介绍了C#语言中的分部类型和可空类型,如声明分部类、结构和接口、分部类型同名成员处理、处理分部类型的基接口、可空类型的属性、可空类型的方法、bool?类型等。其中,读者要着重掌握数组声明分部类和使用可空类型的方法,为后续编写C#程序代码奠定基础。下一章将要介绍C#语言中的隐型变量、初始化器、匿名类型和隐型数组。
15.5 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_15”的控制台应用程序,并实现以下功能。 15.5 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_15”的控制台应用程序,并实现以下功能。 (1)将名称为“class1.cs”的文件添加到该应用程序中。 (2)创建一个名称为“UsingStringNull”的类,并在该类处理可以为空的字符串。
第16章 隐型变量、初始化器、匿名类型和隐型数组 第16章 隐型变量、初始化器、匿名类型和隐型数组 隐型局部变量是使用var关键字声明的一种隐藏类型的局部变量。初始化器包括对象初始化器和集合初始化器,它们分别用来初始化对象和集合。使用new运算符和匿名对象初始化器可以创建一个匿名类型的对象;使用var关键字和匿名数组初始化器可以创建一个隐型数组。本章将讲解C#语言中的隐型局部变量、对象初始化器、集合初始化器、匿名类型和隐型数组,主要介绍以下知识点。 声明隐型局部变量; 使用隐型局部变量; 对象初始化器; 集合初始化器; 匿名类型; 隐型数组。
16.1 隐型局部变量 顾名思义,隐型(implicitly typed)局部变量是一个局部变量,而且它的类型被隐藏了。在隐型局部变量声明中,正被声明的局部变量的类型可以从初始化该变量的表达式推导出来。
16.1.1 声明隐型局部变量 声明隐型局部变量需要使用var关键字,并使用var关键字作为变量的类型。在声明隐型局部变量时,不明确指定该变量的类型,而是使用var关键字指定变量的类型。该变量的实际类型将在其初始化表达式中推导出来。
16.1.2 使用隐型局部变量 使用隐型局部变量可以不显式指定变量的类型,从而简化了程序代码。然而,如果大量使用隐型局部变量,往往可能造成程序代码难以理解和阅读。因此,只有在适当的时候使用隐型局部变量,才是一个比较好的选择。隐型局部变量比较适合以下4种场景。 1.声明隐型局部变量 2.for语句中 3.foreach语句中 4.using语句中
16.2 对象初始化器 对象初始化器(object initializer)又称为对象初始值设定项,它可以为某个对象的零个或多个字段或属性指定值。即对象初始化器不显式调用该对象类型的构造函数,就能够创建该对象类型的实例。 对象初始化器包含一组成员初始值设定项。这一组设定项由“{”和“}”包围,各个设定项之间用,(逗号)分隔。每一个成员初始值设定项都为一个赋值表达式,表达式的左边为成员的名称,表达式的右边是一个可计算的表达式。“ID = 1”表达式就是一个成员初始值设定项,“{ID = 1,Name = "Zhangsan"}”表达式就是一组设定项。
16.3 集合初始化器 集合初始化器(collection initializer)又称为集合初始值设定项,它可以用来设置集合中的元素。集合初始化器包含一组元素初始值设定项。这一组设定项由“{”和“}”包围,各个设定项之间用,(逗号)分隔。每一个元素初始值设定项指定一个元素,“{1,2,3,4,5,6,7,8,9}”表达式就是一组元素初始值设定项。
16.4 匿名类型 顾名思义,匿名类型是一种隐藏了类型名称的类型,它由new运算符和匿名对象初始化器共同实现。即使用new运算符和匿名对象初始化器可以创建一个新的对象,这个新创建的对象就是一个匿名类型的对象。其中,把new运算符和匿名对象初始化器组成的表达式又称为匿名对象创建表达式。
16.5 隐型数组 隐型数组和匿名类型比较相似。和匿名类型的匿名对象初始化器一样,匿名数组也存在一个匿名数组初始化器。匿名对象初始化器一般用于创建一个匿名类型的对象,匿名数组初始化器用来创建一个匿名数组。 匿名数组由var关键字和匿名数组初始化器共同创建,而且匿名数组初始化器中的元素类型都必须能够隐式转换为同一个类型(不能为null)。即对于匿名数组初始化器而言,会存在一种类型(不能为null),使得该匿名数组初始化器中所有元素都能够转换为该类型的元素。
16.6 实例一:在foreach语句中使用隐型局部变量 【实例16-1】在foreach语句中使用隐型局部变量遍历元素类型为string的数组中的每一个元素。该功能由VarForeach()静态方法实现。
16.7 小结 本章主要介绍了C#语言中的隐型变量、初始化器、匿名类型和隐型数组,如声明隐型局部变量、使用隐型局部变量、对象初始化器、集合初始化器、匿名类型、隐型数组等。其中,读者要着重掌握声明隐型局部变量和使用隐型局部变量,为后续编写C#程序代码奠定基础。下一章将要介绍C#语言中的迭代器、匿名方法和扩展方法。
16.8 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_16”的控制台应用程序,并实现以下功能。 16.8 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_16”的控制台应用程序,并实现以下功能。 (1)将名称为“class1.cs”的文件添加到该应用程序中。 (2)在该应用程序中使用隐型数组计算0~100(共101个整数)的和。
第17章 迭代器、匿名方法和扩展方法 迭代器是一个语句块,它可以产生一系列有序值,从而使得foreach语句可以访问该序列。匿名方法是一种特殊的方法,它由delegate关键字、参数列表(可选)和包含在“{”和“}”分隔符中的语句列表组成,并省略了方法的名称。扩展方法可以向现有的类型“添加”新的方法,它是一种静态方法,通过扩展类型的实例来调用扩展方法。本章将讲解C#语言中的迭代器、匿名方法和扩展方法,主要介绍以下知识点。 创建非泛型和泛型迭代器; 非泛型和泛型枚举器; 创建匿名方法; 将匿名方法作为参数传递; 声明扩展方法; 调用扩展方法。
17.1 迭代器 迭代器(iterator)是一个产生(yield)有序值序列的语句块(block)。它也可以通过yield关键字对数组或集合类执行自定义迭代。迭代器包含以下两个特有的语句。 yield return语句,产生迭代的下一个值。 yield break语句,指示迭代完成。 当迭代器执行到yield return语句时,迭代器会保存当前位置。如果该迭代器再一次被调用时,该迭代器将从上述保存的位置重新开始执行。迭代器可以产生一系列的值,而且所有值的类型均相同,该类型称为迭代器的返回类型,又称为产生类型。
17.1.1 创建非泛型迭代器 IEnumerable接口表示公开枚举数,该枚举数支持在非泛型集合上进行简单迭代。IEnumerable接口只包含GetEnumerator()方法,它返回一个循环访问集合的枚举数。创建一个非泛型迭代器最常用的方法是实现IEnumerable接口的GetEnumerator()方法。
17.1.2 创建泛型迭代器 如果要创建一个泛型迭代器,往往需要实现IEnumerable和IEnumerable<T>接口的GetEnumerator()方法。
17.1.3 IEnumerator和IEnumerator<T>接口
17.2 匿名方法 顾名思义,匿名方法(anonymous method)是一种隐藏了名称的方法。在C# 2.0版本之前,声明委托的唯一方法是使用命名方法,即方法必须指定其名称。C# 2.0引入了匿名方法实现了同样的功能,C# 3.0及其以上版本,使用Lambda表达式(第18章)取代了匿名方法,它比匿名方法更加简洁。 匿名方法允许与委托关联的代码以“内联”方式写入使用委托的位置,从而方便地将代码直接“绑定”到委托实例。
17.2.1 创建匿名方法 匿名方法由delegate关键字、参数列表(可选)和包含在“{”和“}”分隔符中的语句列表组成。从匿名方法的组成元素可以看到,匿名方法已经省略了该方法的名称。
17.2.2 将匿名方法作为参数传递 正是因为匿名方法允许与委托关联的代码以“内联”方式,从而使得可以将匿名方法作为方法的参数来传递。
17.3 扩展方法 扩展方法可以使得开发人员能够向现有类型“添加”新的方法,而且不需要创建新的派生类型、重新编译或以其他方式修改原始类型。扩展方法是一种静态方法,可以通过扩展类型的实例来调用扩展方法。
17.3.1 声明扩展方法 声明扩展方法时,需要使用this修饰符。扩展方法的第一个参数指定该方法所作用的类型,并使用this修饰符作为该参数的前缀。
17.3.2 导入扩展方法 导入扩展方法比较简单,只要使用using指令引入扩展方法所在的命名空间即可。实际上,被导入的扩展方法作为其第一个参数的类型上的附加方法。
17.3.3 调用扩展方法 使用using指令导入ToInt32(this string str)扩展方法之后,就可以调用该扩展方法了。
17.4 实例一:扩展string类型的方法 【实例17-1】为string类型扩展了一个方法,该方法的名称为“ToInt32(this string str)”,它可以将一个字符串转换为一个整数。
17.5 小结 本章主要介绍了C#语言中的迭代器、匿名方法和扩展方法,如创建非泛型和泛型迭代器、非泛型和泛型枚举器、创建匿名方法、将匿名方法作为参数传递、声明扩展方法、调用扩展方法等。其中,读者要着重掌握创建非泛型和泛型迭代器和创建匿名的方法,为后续编写C#程序代码奠定基础。下一章将要介绍C#语言中的Lambda表达式和查询表达式。
17.6 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_17”的控制台应用程序,并实现以下功能。 17.6 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_17”的控制台应用程序,并实现以下功能。 (1)将名称为“class1.cs”的文件添加到该应用程序中。 (2)在该应用程序中创建一个泛型迭代器,并使用该迭代器。
第18章 Lambda表达式和查询表达式 C#提供了一种可以用来查询集合、XML、DataSet(数据集)和数据库的技术,并使用Lambda表达式和查询表达式实现这种查询技术。Lambda表达式其实是一种简写的匿名函数,它可以包含表达式和C#语句。查询表达式是一种使用查询语法表示的表达式,它可以从一个或多个给定的数据源中检索数据,并指定检索结果的表现形式。本章将讲解C#语言中的Lambda表达式和查询表达式,主要介绍以下知识点。 Lambda表达式; from子句; select子句; where子句; let子句; orderby子句; group子句; into子句; join子句。
18.1 Lambda表达式 和匿名方法一样,Lambda表达式也是一种匿名函数(anonymous function),它可以包含表达式和语句,并且可用于创建委托或表达式目录树类型。但是,Lambda表达式比匿名方法具有更加简洁的表示形式。Lambda表达式可以由输入参数、Lambda运算符和表达式(或语句块)构成,它的语法形式如下。 (input parameters) => expression; input parameters表示输入参数,它是可选的;“=>”为Lambda运算符(读作“goes to”);expression表示表达式或语句块。
18.1.1 输入参数 在Lambda表达式中,输入参数是Lambda运算符的左边部分。它包含参数的数量可以为0,1或者多个。当输入参数的数量为0时,Lambda表达式的左边部分的一对小括弧不能被省略。
18.1.2 表达式或语句块 在Lambda表达式中,Lambda运算符的右边部分可以是一个表达式或由多个表达式组成的语句块。
18.2 查询表达式 查询表达式(Query expression)是一种使用查询语法表示的表达式,由一组类似与SQL或XQuery的声明性语法编写的子句组成。每一个子句可以包含一个或多个C#表达式,这些C#表达式本身也可能是查询表达式或包含查询表达式。查询表达式包括8个基本子句,具体说明如下。 from子句 select子句 where子句 let子句 orderby子句 group子句 into子句 join子句 查询表达式必须以from子句开头,以select或group子句结束。在第一个from子句和最后一个select子句或group子句之间,可以包含一个或多个where子句、let子句、join子句、orderby子句和group子句,甚至还可以是from子句。
18.2.1 from子句 任何一个查询表达式,不管是否为子查询表达式,它必须包含from子句,且以from子句开头。from子句用来指定查询表达式的数据源和范围变量。数据源不但可以包括查询本身的数据源,而且还可以包括子查询的数据源。范围变量用来表示数据源序列中的每一个元素。 1.数据源 2.包含单个from子句的查询表达式 3.包含多个from子句的查询表达式 4.包含复合from子句的查询表达式
18.2.2 select子句 select子句指定查询结果的类型和表现形式,即指定将在执行查询时产生的值的类型。select子句结果及其表现形式与其前面所有子句的计算结果,以及本身中的所有表达式相关。一个查询表达式要么以select子句结束,要么以group子句结束。
18.2.3 where子句 where子句指定筛选元素的逻辑条件,即用来确定从查询表达式中选择哪些元素。where子句由一个或多个布尔表达式,以及逻辑运算符(如逻辑与、逻辑或等)组成。一个查询表达式可以包含一个或多个where子句。在查询表达式中,where子句不能出现在查询表达式的第一个子句或最后一个子句的位置,其他任何位置都可以放置where子句。
18.2.4 let子句 let子句可以创建一个新的范围变量,用来保存查询表达式中的中间结果。let子句创建的范围变量是一个只读变量,它的值只能通过初始化操作赋值。一旦设定了范围变量的值之后,它的值将不能被修改。当然,可以查询该范围变量的值。
18.2.5 orderby子句 orderby子句可以对查询结果进行排序,排序方式为“升序”(由ascending关键字指定)和“降序”(由descending关键字指定)。
18.2.6 group子句 group子句(使用by关键字)可以对查询的结果进行分组,并返回元素类型为IGrouping<TKey, TElement>的序列。其中,TKey为分组中键的类型,TElement为分组中元素的类型。
18.2.7 into子句 into子句可以创建一个临时标识符,并用来保存group子句、join子句或selet子句的结果,以供其他子句查询该结果。有时,称在group或select子句中使用新标识符的用法为“延续”。
18.2.8 join子句 join子句是查询表达式中比较复杂的一个子句,它和SQL语句中的JOIN子句比较相似,可以用来联接两个数据源,即设置两个数据源之间的关系。一般情况下,这两个数据源是存在相关联的属性或值,以供这两个数据源中的元素进行比较。特别地,join子句可以使用equals关键字比较元素的指定属性是否相等。join子句支持以下3种常见联接方式。 内部联接,元素的联接关系必须同时满足两个数据源,类似于SQL语句中的INNER JOIN子句。 分组联接,包含into子句的join子句。 左外部联接,元素的联接关系必须满足联接中的左数据源,类似于SQL语句中的LEFT JOIN子句。
18.3 实例一:使用Lambda表达式查询XML 【实例18-1】在QueryXml()方法中介绍使用Lambda表达式查询XML类的方法。
18.4 小结 本章主要介绍了C#语言中的查询表达式,如Lambda表达式、from子句、select子句、where子句、let子句、orderby子句、group子句、into子句、join子句等。其中,读者要着重掌握Lambda表达式,以及使用Lambda表达式查询集合、XML文件的方法,为后续编写C#程序代码奠定基础。下一章将要介绍使用C#语言处理字符串的方法。
18.5 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_18”的控制台应用程序,并实现以下功能。 18.5 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_18”的控制台应用程序,并实现以下功能。 (1)将名称为“class1.cs”的文件添加到该应用程序中。 (2)创建一个查询表达式,并使用该查询表达式从一段文本中查询所有单词。
第19章 字符串处理 字符串类型是C#编程语言中最为常用的一种数据类型,.NET Framework为字符串提供了丰富地操作和处理方法。通过这些方法,开发人员可以轻松简单地处理字符串。本章将讲解.NET Framework中处理字符串的方法,主要介绍以下知识点。 String类; StringBuilder类; 不变字符串处理; 可变字符串处理。
19.1 String和StringBuilder类 在.NET Framework中,字符串可以分为两种类型:不变字符串(由String类表示)和可变字符串(由StringBuilder类表示)。不变字符串一旦被创建,那么它的内容是不能被修改的;而可变字符串被创建之后,它的内容是可以动态修改的。
19.1.1 String类 String类表示一系列的有序Unicode字符,用来表示文本。String对象是字符(Char对象)的有序集合,用来表示字符串。String对象的值是该有序集合的内容,并且该值是不可变的,即一旦创建了一个String对象,那么就不能修改该对象的值。虽然有些方法看起来修改了String对象,而实际上是返回了一个包含修改后内容的新的String对象。
19.1.2 StringBuilder类 StringBuilder类表示可变字符串,可以创建能够动态修改(如追加、移除、替换、插入等)的字符串对象。
19.2 不变字符串处理 不变字符串(由String类表示)是不能被修改的。对不变字符串的每一次处理都将产生一个新的字符串。不变字符串处理的方法主要包括插入字符串、移除字符串、替换字符串、联接字符串、分隔字符串、填充字符串等。下面将详细介绍这些方法。
19.2.1 插入字符串 插入字符串是将新的字符串插入到字符串的指定位置,该功能由String类的Insert()方法实现。Insert()方法的原型如下。 public string Insert(int startIndex,string value) 上述方法将value参数指定字符串插入到字符串的startIndex指定的位置。 startIndex参数表示插入的位置(即索引值),value参数表示被插入的新字符串。上述方法返回一个新的字符串。
19.2.2 移除字符串 移除字符串是从字符串中指定位置开始移除其后的所有字符或指定数量的字符,该功能由String类的Remove()方法实现。Remove()方法的原型如下。 public string Remove(int startIndex),从startIndex位置开始移除其后的所有字符。 public string Remove(int startIndex,int count),从startIndex位置开始移除其后的数量为count的字符。
19.2.3 替换字符串 替换字符是指将字符串中指定字符替换为新的字符,或者将指定的字符串替换为新的字符串,该功能由String类的Replace()方法实现。Replace()方法的原型如下。 public string Replace(char oldChar,char newChar),将字符串中指定字符替换为新的字符。 public string Replace(string oldValue,string newValue),将字符串中指定字符串替换为新的字符串。 oldChar参数表示被替换的字符,newChar参数表示替换后的字符。oldValue参数表示被替换的字符串,newValue参数表示替换后的字符串。
19.2.4 联接字符串 联接字符串是将一个或多个字符串对象联接为一个新的字符串,该功能由String类的Concat()方法或Join()方法实现。其中,Concat()方法的最常用的4种原型如下。 public static string Concat(object arg0),联接arg0对象的字符串表示形式,并创建一个新的字符串。 public static string Concat(string str0,string str1),联接str0和str1字符串,并创建一个新的字符串。 public static string Concat(string str0,string str1,string str2),联接str0、str1和str2字符串,并创建一个新的字符串。 public static string Concat(string str0,string str1,string str2,string str3),联接str0、str1、str2和str3字符串,并创建一个新的字符串。
19.2.5 分隔字符串 分隔字符串是将一个字符串被指定的分隔字符或字符串分隔为多个子字符串,并返回由子字符串组成的字符串数组。该功能由String类的Split()方法实现,它的原型如下。 public string[] Split(params char[] separator)。 public string[] Split(char[] separator,int count)。 public string[] Split(char[] separator,StringSplitOptions options)。 public string[] Split(string[] separator,StringSplitOptions options)。 public string[] Split(char[] separator,int count,StringSplitOptions options)。 public string[] Split(string[] separator,int count,StringSplitOptions options)。
19.2.6 填充字符串 填充字符串是向字符串的指定位置填充指定的字符,该功能由String类的PadRight()和PadLeft()方法实现。其中,PadRight()方法在字符串的右边填充字符,PadLeft()方法在字符串的左边填充字符串。由于这两个方法比较相似,下面只将介绍PadLeft()方法。PadLeft()方法的原型如下。 public string PadLeft(int totalWidth),在字符串的左边填充空白字符,填充之后,新字符串的总长度为totalWidth public string PadLeft(int totalWidth,char paddingChar),在字符串的左边填充paddingChar字符,填充之后,新字符串的总长度为totalWidth。
19.2.7 查找字符串 查找字符串是指从字符串中查找指定的字符或子字符串。如果找到,则返回第一个匹配字符或字符串的索引;否则返回-1。该功能由String类的IndexOf()和LastIndexOf()方法实现。其中,IndexOf()方法是从字符串的第一个字符开始依照从头到尾的方式查找,LastIndexOf()方法从字符串的最后一个字符开始依照从尾到头的方式查找。
19.2.8 获取子串 获取子串是指从字符串中获取指定的子字符串,该功能由String类的SubString()方法实现,它的原型如下。 19.2.8 获取子串 获取子串是指从字符串中获取指定的子字符串,该功能由String类的SubString()方法实现,它的原型如下。 public string SubString(int startIndex),获取字符串中从startIndex位置开始的子字符串。 public string SubString(int startIndex,int length),获取字符串中从startIndex位置开始的、最大长度为length的子字符串。
19.2.9 格式化字符串 格式化字符串是指将字符串转化为指定格式的字符串,该功能由String类的Format()方法实现。 19.2.9 格式化字符串 格式化字符串是指将字符串转化为指定格式的字符串,该功能由String类的Format()方法实现。 1.数字格式化 2.日期和时间格式化
19.3 可变字符串处理 可变字符串(由StringBuilder类表示)是一种动态字符串,它是可以被动态修改的。动态修改可变字符串的方法主要包括插入字符串、追加字符串、移除字符串、替换字符串、复制字符串等。下面将详细介绍这些方法。
19.3.1 插入字符串 插入字符串是将新的字符串插入到字符串的指定位置,该功能由StringBuilder类的Insert()方法实现。Insert()方法存在多种原型,常见的原型如下。 public StringBuilder Insert(int index,string value),将value插入到字符串的index指定的位置。 public StringBuilder Insert(int index,string value,int count),将value插入到字符串的index指定的位置,并重复执行该超载count次。
19.3.2 追加字符串 追加字符串是指将指定的字符或字符串追加到字符串的末尾,该功能由StringBuilder类的Append()、AppendLine()和AppendFormat()方法实现。其中,AppendLine()方法在追加指定的字符串之后,还追加一个换行符号;AppendFormat()方法首先格式化被追加的字符串,然后将其追加到字符串。下面仅仅介绍Append()方法的用法。
19.3.3 移除字符串 移除字符串是从字符串中指定位置开始移除其后的指定数量的字符,该功能由StringBuilder类的Remove()方法实现,它的原型如下。 public StringBuilder Remove(int startIndex,int length)。从字符串中startIndex位置处开始移除其后的count个的字符 startIndex参数表示移除的开始位置,count参数表示被移除字符串的最大字符串数量。
19.3.4 替换字符串 替换字符是指将字符串中指定字符替换为新的字符,或者将指定的字符串替换为新的字符串,该功能由StringBuilder类的Replace()方法实现。
19.3.5 复制字符串 复制字符串是指将字符串的内容复制到指定的字符数组中,该功能由StringBuilder类的CopyTo()方法实现,它的原型如下。 public void CopyTo(int sourceIndex,char[] destination,int destinationIndex,int count)。 sourceIndex参数指定被复制字符串中的开始位置;destination参数指定将字符复制到的字符数组,用来保存被复制的字符;destinationIndex参数指定保存复制字符的数组中的起始位置;count参数指定被复制字符的数量。
19.4 实例一:词频统计 【实例19-1】使用处理字符串的方法统计给定一段文本中所有单词出现的频率,并按照此频率倒序显示每一个单词的出现的频率。
19.5 小结 本章主要介绍了使用C#语言处理字符串的方法,如String类、StringBuilder类、不变字符串处理、可变字符串处理等。其中,读者要着重掌握不变字符串处理和可变字符串处理的方法,为后续编写C#程序代码奠定基础。下一章将要介绍C#语言中的日期和时间处理。
19.6 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_19”的控制台应用程序,并实现以下功能。 19.6 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_19”的控制台应用程序,并实现以下功能。 (1)将名称为“class1.cs”的文件添加到该应用程序中。 (2)在该应用程序分别对静态字符串和动态字符串实现查找、插入、替换、移除指定字符串的功能。
第20章 日期和时间处理 日期和时间处理是C#编程中最为常见的操作之一。在.NET Framework中,与日期和时间相关的结构为DateTime和TimeSpan。DateTime结构表示时间上的某一刻,TimeSpan结构表示时间间隔。本章将讲解C#编程中的日期和时间处理,主要介绍以下知识点。 DateTime结构; TimeSpan结构; 格式化日期和时间; 计算日期和时间差; 追加日期和时间。
20.1 DateTime结构 DateTime是一个结构,且为值类型,表示时间上的一刻,包括日期和时间两部分。DateTime表示的值的范围为公元0001年1月1日午夜12:00:00到公元9999年12月31日晚上11:59:59之间的日期和时间。DateTime表示的日期和时间由年、月、日、时、分、秒,以及分隔符组成。最常用的一种格式如下所示。 yyyy-MM-dd hh:mm:ss
20.1.1 字段 DateTime结构只包含两个静态只读字段:MaxValue和MinValue,它们的具体说明如下。 20.1.1 字段 DateTime结构只包含两个静态只读字段:MaxValue和MinValue,它们的具体说明如下。 MaxValue字段,DateTime的最大可能值,它的值为9999年12月31日 23:59:59.9999999。 MinValue字段,DateTime的最小可能值,它的值为0001年1月1日 00:00:00.0000000。
20.1.2 属性 DateTime结构包含16个属性。其中,Now、Today和UtcNow属性为静态属性,其他属性为实例属性。通过这16个属性,可以获取时间的值或时间某一个部分的值,如年份、月份、日期、小时、分钟、秒等。
20.1.3 方法 DateTime结构共包括个38方法,其中,静态方法13个,实例方法25个。
20.2 TimeSpan结构 TimeSpan结构表示一个时间间隔或持续时间,可以按照正负天数、小时数、分钟数、秒数以及秒的小数部分进行度量。 TimeSpan值表示为“[-]d.hh:mm:ss.ff”格式的字符串。减号(可选)表示负时间间隔;d分量表示天数;hh表示小时数(24小时制);mm表示分钟数;ss表示秒的整数部分,ff为秒的小数部分。如“9.1:40:58”表示9天、1小时、40分钟和58秒。
20.2.1 字段 TimeSpan结构包含以下8个静态字段,如MaxValue、MinValue等,它们的具体说明如下。 20.2.1 字段 TimeSpan结构包含以下8个静态字段,如MaxValue、MinValue等,它们的具体说明如下。 MaxValue字段,最大的TimeSpan值,它的值为+10675199.02:48:05.4775807。 MinValue字段,最小的TimeSpan值,它的值为-10675199.02:48:05.4775808。 Zero字段,零TimeSpan值,它的值为00:00:00。常常用于与其他TimeSpan对象的比较。 TicksPerDay字段,一天中的刻度数,它的值为8,640亿。 TicksPerHour字段,1小时的刻度数,它的值为360亿。 TicksPerMinute字段,1分钟的刻度数,它的值为6亿。 TicksPerSecond字段,1秒钟的刻度数,它的值为1,000万。 TicksPerMillisecond字段,1毫秒的刻度数,它的值为1万。
20.2.2 属性 TimeSpan结构包含11个实例属性。通过这11个属性,可以获取TimeSpan对象的天数、小时数、分钟数、秒数、毫秒数等。TimeSpan结构的属性具体说明如表20.4所示。 属性 说明 Days 获取TimeSpan对象的整天数。 Hours 获取TimeSpan对象的整小时数。 Minutes 获取TimeSpan对象的整分钟数。 Seconds 获取TimeSpan对象的整秒数。 Milliseconds 获取TimeSpan对象的整毫秒数。 Ticks 获取TimeSpan对象的刻度数。 TotalDays 获取TimeSpan对象的天数的整数部分和小数部分。 TotalHours 获取TimeSpan对象的小时数的整数部分和小数部分。 TotalMinutes 获取TimeSpan对象的分钟数的整数部分和小数部分。 TotalSeconds 获取TimeSpan对象的秒数的整数部分和小数部分。 TotalMilliseconds 获取TimeSpan对象的毫秒数的整数部分和小数部分。
20.2.3 方法 TimeSpan结构共包括个16方法,其中,静态方法10个,实例方法6个。TimeSpan结构的静态方法具体说明如表20.5所示。 方法 说明 Compare() 比较两个TimeSpan值,它的返回值可以是0、-1或1。 Equals() 判断两个TimeSpan结构的实例是否相等。如果是,则返回true,否则返回false。 FromDays() 根据指定的天数,创建一个TimeSpan结构的实例。 FromHours() 根据指定的小时数,创建一个TimeSpan结构的实例。 FromMinutes() 根据指定的分钟数,创建一个TimeSpan结构的实例。 FromSeconds() 根据指定的秒数,创建一个TimeSpan结构的实例。 FromMilliseconds() 根据指定的毫秒数,创建一个TimeSpan结构的实例。 FromTicks() 根据指定的刻度数,创建一个TimeSpan结构的实例。 Parse() 将一个字符串转换为其相应的TimeSpan对象。 TryParse()
20.3 日期和时间的常用操作 DateTime结构是C#编程中最为常用的一个结构之一。日期和时间的常用操作主要包括日期和时间的格式化、计算日期和时间的差、追加日期和时间等。本小节将详细介绍这些操作。
20.3.1 格式化 日期和时间格式化是指将DateTime结构的实例转换为其相对应的某一种字符串表示形式。DateTime结构提供了多个以“To”开头的方法。这些方法可以将DateTime对象转换为不同格式的字符串形式,常用的方法如表20.7所示。 方法 说明 ToString() 转换为其等效的字符串表示形式。 ToLongDateString() 转换为其等效的长日期字符串表示形式。 ToShortDateString() 转换为其等效的短日期字符串表示形式。 ToLongTimeString() 转换为其等效的长时间字符串表示形式。 ToShortTimeString() 转换为其等效的短时间字符串表示形式。
20.3.2 计算时间差 计算时间差可以使用Subtract()方法。该方法可以计算两个时间的差值,也可以计算时间和时间间隔的差值。它存在以下两种重载形式。 public TimeSpan Subtract(DateTime value),从当前实例中减去指定的日期和时间,返回类型为TimeSpan。其中,value参数表示被减去的日期和时间。 public DateTime Subtract(TimeSpan value),从当前实例中减去指定的时间间隔,返回类型为DateTime。其中,value参数表示被减去的时间间隔。
20.3.3 追加时间 追加时间是指将指定的时间或时间部分(如年份、月份、小时等)追加到一个时间上,并计算出一个新的时间。DateTime结构提供多个以“Add”开头的方法可以实现追加时间的功能,这些方法的具体说明如表20.8所示。 方法 说明 Add() 将指定的TimeSpan的值加到指定的时间上。 AddYears() 将指定的年份数加到指定的时间上。 AddMonths() 将指定的月份数加到指定的时间上。 AddDays() 将指定的天数加到指定的时间上。 AddHours() 将指定的小时数加到指定的时间上。 AddMinutes() 将指定的分钟数加到指定的时间上。 AddSeconds() 将指定的秒数加到指定的时间上。 AddMilliseconds() 将指定的毫秒数加到指定的时间上。 AddTicks() 将指定的刻度数加到指定的时间上。
20.4 实例一:计算for循环的运算时间 【实例20-1】计算for循环的运算时间。该功能由ConsumeTime()方法实现。
20.5 小结 本章主要介绍了C#语言中的日期和时间处理,如DateTime结构、TimeSpan结构、格式化日期和时间、计算日期和时间差、追加日期和时间等。其中,读者要着重掌握格式化日期和时间,以及计算日期和时间差的方法,为后续编写C#程序代码奠定基础。下一章将要介绍.NET Framework中的的IO流、目录和文件处理。
20.6 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_20”的控制台应用程序,并实现以下功能。 20.6 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_20”的控制台应用程序,并实现以下功能。 (1)将名称为“class1.cs”的文件添加到该应用程序中。 (2)获取当前时间,并显示在控制台。 (3)计算一个for语句执行的时间。其中,该for语句执行1000000次。
第21章 IO流、目录和文件处理 IO流、目录和文件处理是系统最为常见的IO操作。IO流为文件、输入/输出设备、内部进程通信管道、TCP/IP套接字提供了操作方法。目录处理包括创建、删除、移动、遍历目录等操作,文件处理包括创建、写入、读取、移动、删除文件等操作。本章将讲解IO流、目录和文件处理,主要介绍以下知识点。 文件流; 内存流; 目录处理; 文件处理。
21.1 IO流 流是字节序列的抽象概念,如文件、输入/输出设备、内部进程通信管道、TCP/IP套接字等。Stream类是所有流的抽象基类,它可以为流提供一般性视图,从而使得开发人员不需要了解IO设备的具体细节。与流相关的操作包括以下3个基本操作。 读取流,即读取流中的内容。 写入流,即将指定的内容写入到流中。 流支持查找,即可以查找或设置流的当前位置。
21.1.1 文件流 FileStream(文件流)类公开以文件为主的Stream,它既支持同步读写操作,也支持异步读写操作。使用文件流可以对文件进行读取、写入、打开和关闭操作,以及系统相关操作的标准输入、标准输出等。 FileStream类包括9个属性,它们可以描述FileStream类的实例的特性,如流的长度(以字节为单位)、流的当前位置、是否能够读或写或查询等。FileStream类的属性的具体说明如表21.1所示。
21.1.2 内存流 MemoryStream类可以用来创建其支持存储区为内存的流。它可以封装内存中的存储的数据,这些数据的表现形式为无符号字节数组。并且,通过MemoryStream类的实例可以直接在内存中访问该数组。特别地,使用内存流可以降低应用程序对临时缓冲区和临时文件的需要。
21.2 目录处理 在.NET Framework中,用来处理目录的类主要包括Directory和DirectoryInfo类。Directory类是一个静态类,它公开用于创建、移动、枚举目录和子目录的静态方法。DirectoryInfo类是一个密封类,从FileSystemInfo类派生,并公开用于创建、移动、枚举目录和子目录的实例方法。
21.2.1 Directory类 Directory类是一个静态类,它只包含多个静态方法,用来创建、移动、枚举目录和子目录。其中,常用的静态方法具体说明如表21.5所示。 方法 说明 CreateDirectory() 创建指定路径的目录。 Delete() 删除指定的目录。 Exists() 判断指定路径的目录是否存在。如果存在,返回true,否则返回false。 Move() 将指定文件或目录及其内容移到新位置。 GetParent() 获取指定路径的父目录。 GetCurrentDirectory() 获取应用程序的当前工作目录。 SetCurrentDirectory() 设置应用程序的当前工作目录。 GetDirectories() 获取指定目录中子目录。 GetDirectoryRoot() 获取指定路径的卷信息或根信息。 GetFiles() 获取指定目录中的文件。 GetFileSystemEntries() 获取指定目录中所有文件和子目录。 GetLogicalDrives() 获取当前计算机上的逻辑驱动器。 GetCreationTime() 获取目录的创建日期和时间。 SetCreationTime() 设置指定的文件或目录的创建日期和时间。 GetLastAccessTime() 获取上次访问指定文件或目录的日期和时间。 SetLastAccessTime() 设置上次访问指定文件或目录的日期和时间。 GetLastWriteTime() 获取上次写入指定文件或目录的日期和时间。 SetLastWriteTime() 设置上次写入目录的日期和时间。
21.2.2 DirectoryInfo类 DirectoryInfo类是一个密封类,它可以用来创建、移动、枚举目录和子目录。DirectoryInfo类包括4个属性,可以用来获取目录的名称、父目录等,具体说明如表21.6所示。 属性 说明 Exists 判断指定目录是否存在。如果存在,则返回true,否则返回false。 Name 获取目录的名称。 Parent 获取指定子目录的父目录。 Root 获取路径的根部分。
21.2.3 创建目录 创建目录可以使用以下3种方法中的任何一种。 21.2.3 创建目录 创建目录可以使用以下3种方法中的任何一种。 Directory类的CreateDirectory()方法,用来创建一个目录。 DirectoryInfo类的Create()方法,用来创建一个目录。 DirectoryInfo类的CreateSubdirectory()方法,用来创建一个指定目录下的子目录。
21.2.4 删除目录 删除目录可以使用以下2种方法中的任何一种。 Directory类的Delete()方法,用来删除一个目录。 21.2.4 删除目录 删除目录可以使用以下2种方法中的任何一种。 Directory类的Delete()方法,用来删除一个目录。 DirectoryInfo类的Delete()方法,用来删除一个目录。 Directory类的Delete()方法存在以下两个原型。 public static void Delete(string path),删除path指定的目录,且该目录必须为空目录。 public static void Delete(string path,bool recursive),删除path指定的目录。recursive参数指定是否删除该目录下的所有内容(如子目录、文件等)。
21.2.5 移动目录 移动目录可以使用以下2种方法中的任何一种。 21.2.5 移动目录 移动目录可以使用以下2种方法中的任何一种。 Directory类的Move()方法,将指定文件或目录及其内容移到新位置。 DirectoryInfo类的MoveTo()方法,将指定目录及其内容移到新位置。
21.2.6 遍历目录 遍历目录是指获取该目录下的子目录或文件,主要存在一下6种方法。 21.2.6 遍历目录 遍历目录是指获取该目录下的子目录或文件,主要存在一下6种方法。 Directory类的GetDirectories()方法,获取指定目录中子目录。 Directory类的GetFiles()方法,获取指定目录中的文件。 Directory类的GetFileSystemEntries()方法,获取指定目录中所有文件和子目录。 DirectoryInfo类的GetDirectories()方法,获取当前目录的子目录。 DirectoryInfo类的GetFiles()方法,获取当前目录的文件。 DirectoryInfo类的GetFileSystemInfos()方法,获取当前目录的所有文件和子目录。
21.3 文件处理 在.NET Framework中,用来处理文件的类主要包括File和FileInfo类。File类是一个静态类,它提供用于创建、复制、删除、移动和打开文件的静态方法。FileInfo类是一个密封类,从FileSystemInfo类派生,并提供创建、复制、删除、移动和打开文件的实例方法。
21.3.1 File类 File类是一个静态类,它只包含多个静态方法,用来创建、复制、删除、移动和打开文件。
21.3.2 FileInfo类 FileInfo类是一个密封类,它可以用来创建、复制、删除、移动和打开文件的实例方法。FileInfo类包括6个属性,可以用来获取文件的名称、完整路径等,具体说明如表21.9所示。 属性 说明 Directory 获取父目录。 DirectoryName 获取文件的完整路径。 IsReadOnly 获取或设置当前文件是否为只读。 Exists 指定当前文件是否存在。 Length 获取当前文件的大小(字节)。 Name 获取文件的名称。
21.3.3 创建文件 创建文件可以使用File类的Create()方法或者FileInfo类的Create()方法。 21.3.3 创建文件 创建文件可以使用File类的Create()方法或者FileInfo类的Create()方法。 【示例21-18】使用FileInfo类的Create()方法创建一个名称为“my.ini”的文件。 FileInfo fi = new FileInfo("my.ini"); fi.Create();
21.3.4 写入文件 存在多种方法,可以将指定内容写入到文件,如File类的OpenWrite()方法、FileInfo类的OpenWrite()方法等。
21.3.5 读取文件 存在多种方法,可以从指定文件中读取内容,如File类的OpenRead()方法、FileInfo类的OpenRead()方法等。 【示例21-20】使用FileInfo类的OpenRead()方法从my.ini文件读取内容,并转换为一个字符串(保存为valuer),最终,将valuer的内容显示在控制台。
21.3.6 移动文件 移动文件可以使用以下2种方法中的任何一种。 File类的Move()方法,将指定文件移到新位置。 21.3.6 移动文件 移动文件可以使用以下2种方法中的任何一种。 File类的Move()方法,将指定文件移到新位置。 FileInfo类的MoveTo()方法,将指定文件移到新位置。
21.3.7 删除文件 删除文件可以使用以下2种方法中的任何一种。 File类的Delete()方法,将删除指定的文件。 21.3.7 删除文件 删除文件可以使用以下2种方法中的任何一种。 File类的Delete()方法,将删除指定的文件。 FileInfo类的Delete()方法,将删除指定的文件。
21.4 实例:读取目录下指定类型的文件的内容 【实例21-1】实现了读取指定目录下的、指定文件类型的、所有文件的内容,并在控制台中显示读取的内容。
21.5 小结 本章主要介绍了.NET Framework中的IO流、目录和文件处理,如文件流、目录流、目录处理、文件处理等。其中,读者要着重掌握目录处理和文件处理,为后续编写对文件操作的C#应用程序代码奠定基础。下一章将要介绍C#语言的Windows窗体编程。
21.6 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_21”的控制台应用程序,并实现以下功能。 21.6 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_21”的控制台应用程序,并实现以下功能。 (1)将名称为“class1.cs”的文件添加到该应用程序中。 (2)在class1.cs文件中是实现使用二进制方法对“readme.txt”文件的读写方法。
第22章 Windows窗体编程 Windows窗体应用程序是基于Microsoft Windows平台至上一种经典的可视化应用程序,它特别适合于包含丰富图形用户界面的应用程序。Windows窗体应用程序运行之后,往往会显示一个或多个的Windows窗体,具有友好的交互功能。使用.NET Framework和C#语言可以开发功能强大的Windows窗体应用程序。本章节主要介绍以下知识点。 Windows窗体应用程序概述; Windows窗体基本控件; MainForm.cs窗体设计; 菜单和工具栏; 容器; 对话框; 数据网格视图控件; 运行Sample_22应用程序。
22.1 Windows窗体应用程序概述 本节介绍使用Microsoft Visual Studio 2008集成开发环境(IDE)创建Sample_22 Windows窗体应用程序的方法,以及该Windows窗体应用程序的起始点(Program.cs文件)、配置信息(AssemblyInfo.cs文件)等。
22.1.1 创建Sample_22 Windows窗体应用程序 依次选择“开始”|“所有程序”|“Microsoft Visual Studio 2008”|“Microsoft Visual Studio 2008”命令,打开“起始页 - Microsoft Visual Studio”窗口。单击“最近项目”面板中的“创建”下的“项目”链接,弹出“新建项目”对话框,如图22.1所示。
22.1.2 应用程序起始点 双击“解决方案资源管理器”面板中的“Program.cs”节点,打开Program.cs文件。该文件为Sample_22 Windows窗体应用程序提供主入口点。
22.1.3 配置程序集信息 首先展开“解决方案资源管理器”面板中的“Properties”节点,然后双击“AssemblyInfo.cs”节点打开AssemblyInfo.cs文件。该文件用来配置Sample_22 Windows窗体应用程序的程序集信息。
22.2 基本控件 本小节对Windows窗体的基本控件做一个简单介绍。这些基本控件包括标签控件、图片框控件、文本框控件、富文本框控件、按钮控件、单项按钮和复选框。
22.2.1 标签控件 标签(Label)控件是最为简单的Windows窗体控件,它可以用来显示不能编辑的文本或图像。标签控件不能接收焦点,但是可以作为其他控件的访问键。
22.2.2 图片框控件 图片框(PictureBox)控件可以用来显示位图、GIF、JPEG、图元文件或图标格式的图形,它显示的图片由Image属性指定,也可以由ImageLocation属性指定被显示图片的地址(在显示指定的图片时,由Load()方法实现)。
22.2.3 文本框和富文本框 文本框(TextBox)控件可以用来获取用户输入或显示文本。文本框可以用来编辑文本,也可以以只读方式显示文本。文本框通常显示为单行,但也可以显示多个行。通过Text属性可以获取或设置文本框的输入或显示的文本。 富文本框(RichTextBox)控件和文本框相比,它能够处理有格式的文本,还可以显示字体、颜色、链接、嵌入的图像等。实际上,富文本框能够提供类似字处理应用程序的文本操作和显示功能,如复制、剪切、粘贴、全选等。
22.2.4 按钮控件 按钮(Button)控件允许用户通过单击来执行操作。每当用户单击按钮时,即调用该按钮事先定义的Click事件处理程序。按钮显示的文本可以通过其Text属性指定,另外,按钮还可以使用Image或者ImageList属性显示图像。
22.2.5 单项按钮和复选框 单项按钮由RadioButton类实现,可以为用户提供由两个或多个互斥选项组成的选项集。多个单选框可以组合为一个组。对于同一组内的所有单项按钮而言,用户一次只能选中一个单项按钮。复选框由CheckBox类实现,它可以用来指定某个条件是打开的还是关闭的,即常常用来提供“是/否”或者“真/假”选项。多个复选框也可以组合为一个组,用户可以选择该组中的一个或多个复选框。
22.3 MainForm.cs窗体设计 本小节介绍设计MainForm.cs窗体的方法,包括配置窗体的属性(如名称、标题等)、添加控件(如标签控件、按钮控件、图片框控件等)、创建新窗口(如等待对话框等)等方法。
22.3.1 配置窗体属性 打开“解决方案资源管理器”面板,并将“Form1.cs”节点重命名为“MainForm.cs”节点。双击该节点打开MainForm.cs窗体的设计界面。单击MainForm.cs窗体,“属性”面板将显示该窗体的各种属性及其值。开发人员还可以通过“属性”面板配置该窗体的各种属性。在此,笔者将MainForm.cs窗体的Name属性的值设置为“MainForm”、Text属性的值设置为“Windows窗体编程”,如图22.3所示。
22.3.2 添加控件 选择“工具箱”中的某一个控件,并直接拖放到MainForm.cs窗体之上,就可以把该控件添加到MainForm.cs窗体。在此,笔者向MainForm.cs窗体添加了多个控件,并设置了相应的事件。
22.3.3 创建等待对话框 下面介绍创建等待对话框(由WaittingForm.cs窗体实现)的具体步骤。
22.3.4 添加窗体事件 打开MainForm.cs窗体的设计界面,并双击该窗体就可以为该窗体添加MainForm_Load(object sender, EventArgs e)事件。当系统加载MainForm.cs窗体时,将触发该事件。
22.4 菜单和工具栏 本小节介绍Windwos系统中最为熟悉的3个控件:菜单(由MenuStrip类实现)、工具栏(由ToolStrip类实现)和上下文菜单(由ContextMenuStrip类实现)的使用方法。
22.4.1 菜单 菜单由MenuStrip类实现,它可以通过存放按照一般主题分组的命令将功能公开给用户。使用菜单可以轻松实现以下3个功能。 22.4.1 菜单 菜单由MenuStrip类实现,它可以通过存放按照一般主题分组的命令将功能公开给用户。使用菜单可以轻松实现以下3个功能。 创建支持高级用户界面和布局功能的易自定义的常用菜单。 支持操作系统的典型外观和行为。 对所有容器和包含的项进行事件的一致性处理。
22.4.2 工具栏 工具栏由ToolStrip类型实现,它可以为Windows窗体实现工具栏的功能。并且,还可以向工具栏添加按钮、下拉按钮、分割栏、文本框、下拉列表等控件。
22.4.3 上下文菜单 上下文菜单由ContextMenuStrip类型实现。当用户单击鼠标右键时,将在鼠标位置显示上下文菜单。如果要为某一个窗体添加上下文菜单,只要将上下文菜单(ToolStrip)控件从“工具箱”面板中直接拖放到窗体上即可。
22.5 容器 本小节主要介绍Windwos系统中最为熟悉的3个容器控件:面板(由Panel类实现)、组合框(由GroupBox类实现)和选项卡(由TabControl和TabPage类实现)的使用方法。
22.5.1 面板 面板(Panel)控件是一个容器控件,可以用来包含其他控件,即可以使用面板控件来组合控件的集合。默认情况下,面板控件不显示任何边框。如果要显示边框,则需要设置其BorderStyle属性的值。特别地,面板控件不显示标题。面板控件包括以下3个常用属性。 AutoSizeMode属性,指定控件的自动调整大小行为。 BorderStyle属性,指定控件的边框样式。 TabStop属性,指定用户能否使用Tab键将焦点放到该控件上。
22.5.2 组合框 组合框(GroupBox)控件和面板控件比较相似,也可以用在其他控件的容器控件。它可以显示围绕一组具有可选标题的控件的框架,并且还可以显示标题。组合框控件最典型的用途是用作一组单项按钮的容器,并指定为以一个逻辑组,组内的单项按钮互相排斥。组合框控件包括以下8个常用属性。 AllowDrop属性,指定控件是否允许使用拖放操作和事件。 AutoSize属性,指定控件是否根据其内容调整大小。 AutoSizeMode属性,当控件启用AutoSize属性时,指定控件的行为方式。 DisplayRectangle属性,获取控件的维度的矩形。 FlatStyle属性,获取或设置控件的平面样式外观。 TabStop属性,指定用户能否使用Tab键将焦点放到该控件上。 Text属性,控件的标题。 UseCompatibleTextRendering属性,指定是否使用了兼容文本呈现控件的标题。
22.5.3 TabControl控件 TabControl控件可以显示多个选项卡,每一个选项卡都包含一个选项卡页(TabPage)控件,而且每一个选项卡页可以包含其他控件。单击每一个选项卡的标题可以设置它的选项卡页为当前选项卡页。选项卡是TabControl控件的一部分,但不是各个选项卡页的一部分。选项卡页控件的属性只影响选项卡页的矩形工作区,而不影响选项卡。TabControl控件包括以下3个常用属性。 SelectedIndex属性,当前选定的选项卡页的索引。 SelectedTab属性,当前选定的选项卡页。 TabPages属性,TabControl控件中选项卡页的集合。
22.5.4 容器窗体 容器窗体由ContainForm.cs窗体实现,介绍了面板、组合框、选项卡等控件的使用方法。该窗体的标题为“容器”,它包括1个TabControl控件、3个Tabpage、1个TextBox控件、1个RichTextBox控件、1个PictureBox、1个GroupBox、3个RadioButton和2个Panel控件。
22.6 对话框 对话框(Dialog)是一种特殊的窗体(其FormBorderStyle属性的值为FormBorderStyle.FixedDialog),常常用于与用户交互和检索信息。本小节介绍Windows应用程序最为常用的5种对话框:颜色对话框、字体对话框、打开文件对话框、保存文件对话框和目录浏览对话框。
22.6.1 对话框窗体 对话框窗体由DialogForm.cs窗体实现。用户单击该对话框中的“设置颜色”、“设置字体”、“浏览文件…”、“保存为…”和“浏览目录…”按钮分别弹出颜色对话框、字体对话框、打开文件对话框、保存文件对话框和目录浏览对话框。
22.6.2 颜色对话框 颜色对话框由Windows窗体ColorDialog组件实现,它是一个预先设置的对话框。用户可以从该对话框的调色板中选择颜色,以及将自定义颜色添加到该调色板。如果开发基于Windows的应用程序,开发人员可以使用该对话框来实现选择颜色功能,而不需要再配置自己的对话框。 颜色对话框包括7个常用属性,如获取颜色对话框中选择的颜色的Color属性、禁用“定义自定义颜色”按钮的AllowFullOpen属性等。
22.6.3 字体对话框 字体对话框由Windows窗体ColorDialog组件实现,它也是一个预先设置的对话框。用户可以从该对话框中选择系统上当前安装的字体。通过该对话框,用户可以设置文本的字体、样式、大小、脚本和效果。字体对话框包括5个常用属性,具体说明如表22.5所示。 属性 描述 Font 用户选定的字体。 Color 用户选定的字体颜色。 MaxSize 用户可选择的最大磅值。 MinSize 用户可选择的最小磅值。 ShowHelp 指示是否显示“帮助”按钮。
22.6.4 打开文件对话框 打开文件对话框由Windows窗体OpenFileDialog组件实现,它与Windows操作系统所公开的“打开文件”对话框相同。打开文件对话框包括5个常用属性,具体说明如表22.6所示。 属性 描述 Multiselect 是否允许选择多个文件。 ReadOnlyChecked 是否选定只读复选框。 SafeFileName 所选文件的文件名和扩展名。 SafeFileNames 所有选定文件的文件名和扩展名的数组。 ShowReadOnly 是否包含只读复选框。
22.6.5 保存文件对话框 保存文件对话框由Windows窗体SaveFileDialog组件实现,它与Windows使用的标准“保存文件”对话框相同。保存文件对话框包括2个常用属性,具体说明如表22.7所示。 属性 描述 CreatePrompt 如果用户指定不存在的文件,对话框是否提示用户允许创建该文件。 OverwritePrompt 如果用户指定的文件名已存在,保存文件对话框是否显示警告。
22.6.6 目录浏览对话框 目录浏览对话框由Windows窗体FolderBrowserDialog组件实现,它可以显示一个用于浏览和选择文件夹的模式对话框。用户可以从该对话框中选择文件夹。目录浏览对话框包括4个常用属性,如获取用户所选择文件夹的路径的SelectedPath属性、启用“新建文件夹”按钮的ShowNewFolderButton属性等。这些常用属性的具体说明如表22.8所示。 属性 描述 SelectedPath 用户选定的路径。 ShowNewFolderButton 指示是否显示“新建文件夹”按钮。 Description 对话框中在树视图控件上显示的说明文本。 RootFolder 从其开始浏览的根文件夹。
22.7 数据网格视图控件 数据网格视图控件窗体由DGVForm.cs窗体实现,该窗体使用DataGridView(数据网格视图)控件显示数据。DGVForm.cs窗体的标题为“数据网格视图控件”,它只包含1个DataGridView控件(Name属性的值为dgvData)。 运行Sample_22 Windows窗体应用程序之后,单击“数据网格视图”命令打开“数据网格视图控件”对话框(DGVForm.cs窗体),如图22.26所示。
22.8 运行应用程序 按下“F5”按钮或者单击Microsoft Visual Studio 2008集成开发环境中的按钮即可运行Sample_22 Windows窗体应用程序。该应用程序运行之后,显示的第一个窗口为“Form1”窗口,如图22.27所示。
22.9 小结 本章主要介绍了Windows窗体应用程序,如Windows窗体应用程序概述、Windows窗体基本控件、MainForm.cs窗体设计、菜单和工具栏、容器、对话框、数据网格视图控件等。其中,读者要着重掌握Windows窗体基本控件、菜单、工具栏、容器、对话框和数据网格视图控件的使用方法,为后续编写功能强大的Windows应用程序奠定基础。下一章将要介绍.NET Framework中的GDI+绘图技术。
22.10 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_22”的Windows应用程序,并实现等待对话框的功能。
第23章 使用GDI+绘图 GDI+是.NET Framework中专门用于绘制线条和形状、呈现文本或显示与操作图像的技术。Graphics类封装一个GDI+绘图图面,Graphics对象和点、区域、颜色、刷、画笔、字体等结构或类提供将对象绘制到显示设备的方法。本章节主要介绍以下知识点。 Graphics类; 点、区域、颜色、刷、画笔和字体; 绘制直线、虚线和曲线; 绘制多边形和椭圆; 绘制饼状图; 绘制文本。
23.1 GDI+概述 GDI+是Windows XP操作系统中提供二维矢量图形、图像处理和版式的部分。.NET Framework为操作图形提供了GDI+应用程序编程接口,GDI+是 Windows图形设备接口(GDI)的高级实现,通过使用GDI+,开发人员可以创建图形、绘制文本,以及以对象的方式来操作图形或图像。
23.1.1 Graphics类 Graphics类封装一个GDI+绘图图面,提供将对象绘制到显示设备的方法,是可以用来创建图形图像的对象。通常,Graphics对象与特定的设备上下文关联。 1.创建Graphics对象 2.绘制图形、文本或图像 3.填充图形或图像
23.1.2 点和区域 在GDI+中,二维图像都基于一个二维平面中,并使用点、矩形、区域来描述这些图像。这个二维平面的坐标系如图23.1所示。平面的左上角为坐标系的原点,水平朝右的方向表示X轴的正方向,垂直朝下的方向表示Y轴的正方向。 1.Point和PointF结构 2.Rectangle和RectangleF结构 3.Size和SizeF结构 4.Region类
23.1.3 颜色 Color(颜色)结构表示一种ARGB颜色,它由4个分量值(alpha、红色、绿色和蓝色)组成。Color结构包括多个方法,如用来创建颜色的FromArgb()方法、FromKnownColor()方法、FromName()方法等。
23.1.4 刷 Brush(刷)类定义用于填充图形形状(如矩形、椭圆、饼形、多边形和封闭路径)的内部的对象。 23.1.4 刷 Brush(刷)类定义用于填充图形形状(如矩形、椭圆、饼形、多边形和封闭路径)的内部的对象。 注意:Brush类是一个抽象基类,不能进行实例化。若要创建一个刷的实例,必须使用从Brush派生出的类,如SolidBrush、TextureBrush、LinearGradientBrush类等。
23.1.5 画笔 Pen(画笔)类定义用于绘制直线和曲线的对象,还可以指定直线的宽度、样式等。要创建一个画笔可以使用Pen类的构造函数。Pen类包括4个构造函数,具体说明如下。 public Pen(Brush brush),使用刷创建画笔。brush参数指定画笔所使用的刷。 public Pen(Color color),使用颜色创建画笔。color参数指定画笔所使用的颜色。 public Pen(Brush brush,float width),使用刷创建画笔。brush参数指定画笔所使用的刷,width参数指定画笔的宽度。 public Pen(Color color,float width),使用颜色创建画笔。color参数指定画笔所使用的颜色,width参数指定画笔的宽度。
23.1.6 字体 Font(字体)类定义特定的文本格式,包括字体、字号和字形属性。创建字体可以使用Font类的构造函数。
23.2 实例一:使用GDI+绘制线条、形状和文本 【实例23-1】使用GDI+中的Graphics对象对象在Panel控件上绘制直线、折线、曲线、虚线、矩形、三角形、多边形、椭圆、饼状图和文本。下面介绍具体实现方法。
23.2.1 创建Sample_23窗体应用程序 【实例23-1】创建了名称为“Sample_23”的Windows Form应用程序。
23.2.2 Paint事件 当重绘Panel控件时,会触发Paint事件。该事件由Control类(控件的基类)提供,Panel类继承该事件。在Sample_23窗体应用程序中,笔者为pChart控件添加了Paint事件,并在该事件中为pChart控件的顶部绘制了3D边界。该事件的名称为pChart_Paint(object sender,PaintEventArgs e)。
23.2.3 绘制直线 单击MainForm窗体中的“绘制直线”按钮可以在pChart控件中绘制一条直线。该功能由“绘制直线”按钮的Click事件——btnDrawLine_Click(object sender,EventArgs e)实现。
23.2.4 绘制折线 单击MainForm窗体中的“绘制折线”按钮可以在pChart控件中绘制一条折线。该功能由“绘制折线”按钮的Click事件——btnDrawLines_Click(object sender,EventArgs e)实现。
23.2.5 绘制曲线 单击MainForm窗体中的“绘制曲线”按钮可以在pChart控件中绘制一条曲线。该功能由“绘制曲线”按钮的Click事件——btnDrawCurve_Click(object sender,EventArgs e)实现。
23.2.6 绘制虚线 单击MainForm窗体中的“绘制虚线”按钮可以在pChart控件中绘制一条虚线。该功能由“绘制虚线”按钮的Click事件——btnDrawDashLine_Click(object sender,EventArgs e)实现。
23.2.7 绘制矩形 单击MainForm窗体中的“绘制矩形”按钮可以在pChart控件中绘制一个矩形。该功能由“绘制矩形”按钮的Click事件——btnDrawRect_Click(object sender,EventArgs e)实现。
23.2.8 绘制三角形 单击MainForm窗体中的“绘制三角形”按钮可以在pChart控件中绘制一个三角形。该功能由“绘制三角形”按钮的Click事件——btnDrawTriangle_Click(object sender,EventArgs e)实现。
23.2.9 绘制多边形 单击MainForm窗体中的“绘制多边形”按钮可以在pChart控件中绘制一个多边形。该功能由“绘制多边形”按钮的Click事件——btnDrawPolygon_Click(object sender,EventArgs e)实现。
23.2.10 绘制椭圆 单击MainForm窗体中的“绘制椭圆”按钮可以在pChart控件中绘制一个椭圆。该功能由“绘制椭圆”按钮的Click事件——btnDrawEllipse_Click(object sender,EventArgs e)实现。
23.2.11 绘制饼状图 单击MainForm窗体中的“绘制饼状图”按钮可以在pChart控件中绘制一个饼状图。该功能由“绘制饼状图”按钮的Click事件——btnDrawPie_Click(object sender,EventArgs e)实现。
23.2.12 绘制文本 单击MainForm窗体中的“绘制文本”按钮可以在pChart控件中绘制一段文本“这是一段文本。”。该功能由“绘制文本”按钮的Click事件——btnDrawString_Click(object sender,EventArgs e)实现。
23.3 小结 本章主要介绍了NET Framework中的GDI+绘制技术,如Graphics类、区域、颜色、刷、画笔、字体等,以及绘制直线、虚线、曲线、多边形、椭圆、饼状图和文本。其中,读者要着重掌握使用GDI+绘制直线、虚线、曲线、多边形、椭圆、饼状图和文本的方法,为后续编写功能强大的Windows应用程序奠定基础。下一章将要介绍.NET Framework中的数据访问。
23.4 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_23”的控制台应用程序,并实现以下功能。 23.4 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_23”的控制台应用程序,并实现以下功能。 (1)创建名称为“MyForm.cs”的窗体。 (2)在在名称为“MyForm.cs”窗体上绘制以下图形。 直线; 折线; 曲线; 虚线; 矩形; 三角形; 多边形; 椭圆; 圆; 扇形; 饼状图; 文本。
第24章 .NET数据访问 .NET数据访问是.NET Framework中很重要的一个功能,它由ADO.NET实现。通过ADO.NET,开发人员可以访问Microsoft SQL Server、ODBC、Oracle、OLE DB、XML等数据源,并检索、操作和更新这些数据源中的数据。本章节主要介绍以下知识点。 ADO.NET组成结构; ADO.NET基本对象,如SqlCommand、SqlDataReader、SqlDataAdpater、DataSet等对象; 使用ADO.NET操作SQL Server数据库,包括连接、读取、插入、修改、删除等操作; 使用DataGridView控件显示数据; 使用ListView控件显示数据; 使用TreeView控件显示数据。
24.1 ADO.NET概述 ADO.NET是.NET Framework中提供了专门用来处理数据的技术。通过该技术,开发人员可以访问SQL Server、ODBC、Oracle、OLE DB、XML等数据源,并检索、操作和更新这些数据源中的数据。
24.1.1 ADO.NET组成结构 ADO.NET是.NET Framework中的一部分,它提供对Microsoft SQL Server、ODBC、Oracle等数据源,以及通过OLE DB和XML公开的数据源的一致访问。应用程序(Windows Form、ASP.NET等)可以使用ADO.NET来连接到这些数据源,并检索、操作和更新其中的数据。ADO.NET组成结构如图24.1所示。 1..NET Framework数据提供程序 2.DataSet(数据集)
24.1.2 ADO.NET基本对象 ADO.NET基本对象主要包括Connection、Command、DataReader、DataAdapter、DataSet、DataView等对象。本小节只介绍用于操作SQL Server数据库相关的SqlConnection、SqlCommand、SqlDataReader、SqlDataAdapter、DataSet、DataView等。 1.SqlConnection对象 2.SqlCommand对象 3.SqlDataReader对象 4.DataSet对象
24.2 实例一:操作SQL Server数据库 【实例24-1】使用ADO.NET实现了操作SQL Server 2005数据库的功能,包括连接数据库、读取数据、插入数据、修改数据、删除数据、使用DataGirdView控件显示数据、使用ListView控件显示数据和使用TreeView控件显示数据。
24.2.1 创建Sample_24窗体应用程序 【实例24-1】创建了名称为“Sample_24”的Windows Form应用程序。
24.2.2 创建CSharp3DB数据库 Sample_24 Windows Form应用程序连接了名称为“CSharp3DB”的SQL Server 2005数据库,并操作了该数据库中的数据。
24.2.3 连接数据库 单击MainForm窗体中的“连接数据库”按钮可以连接CSharp3DB数据库。该功能由“连接数据库”按钮的Click事件——btnConnect_Click(object sender,EventArgs e)实现。
24.2.4 读取数据 单击MainForm窗体中的“读取数据”按钮可以读取CSharp3DB数据库的Data表中的所有数据,并显示在rtbMessage控件中。该功能由“读取数据”按钮的Click事件——btnReadData_Click(object sender,EventArgs e)实现。
24.2.5 插入数据 单击MainForm窗体中的“插入数据”按钮可以向CSharp3DB数据库的Data表中插入新的数据。该功能由“插入数据”按钮的Click事件——btnInsertData_Click(object sender,EventArgs e)实现。
24.2.6 修改数据 单击MainForm窗体中的“修改数据”按钮可以修改CSharp3DB数据库的Data表中的数据。该功能由“修改数据”按钮的Click事件——btnUpdateData_Click(object sender,EventArgs e)实现。
24.2.7 删除数据 单击MainForm窗体中的“删除数据”按钮可以删除CSharp3DB数据库的Data表中的数据。该功能由“删除数据”按钮的Click事件——btnDeleteData_Click(object sender,EventArgs e)实现。
24.2.8 使用DataGridView控件显示数据 单击MainForm窗体中的“显示数据”按钮可以在DataGridView控件中显示CSharp3DB数据库的Data表中的数据。该功能由ShowDataWithDataGirdView()方法实现。
24.2.9 使用ListView控件显示数据 单击MainForm窗体中的“显示数据”按钮可以在ListView控件中显示CSharp3DB数据库的Data表中的数据。该功能由ShowDataWithListView()方法实现。
24.2.10 使用TreeView控件显示数据 单击MainForm窗体中的“显示”按钮可以在TreeView控件中显示CSharp3DB数据库的Data表中的数据。该功能由ShowDataWithTreeView()方法实现。
24.3 小结 本章主要介绍了.NET Framework中中的数据访问功能,如ADO.NET组成结构、ADO.NET基本对象、使用ADO.NET操作SQL Server数据库、使用DataGridView控件显示数据、使用ListView控件显示数据、使用TreeView控件显示数据等。其中,读者要着重掌握ADO.NET基本对象,以及使用ADO.NET操作SQL Server数据库的方法,为后续编写功能强大的、处理数据(特别是处理数据库中的数据)的C#程序代码奠定基础。下一章将要介绍使用C#语言开发图书管理系统的方法。
24.4 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_24”的Windows应用程序,并实现以下功能。 24.4 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_24”的Windows应用程序,并实现以下功能。 (1)将名称为“Form1.cs”的窗体添加到该应用程序中。 (2)使用Form1.cs窗体实现用户管理功能(包括查询、添加、修改和删除用户)。其中,用户表User保存在名称为“UserDB”的SQL Server 2005数据库中,且该表包含3个列:ID、Username和Password。
第25章 图书管理系统 图书管理系统是当前最为流行的管理系统之一,它一般包括登录、主窗口、图书分类管理、书籍管理、借阅书籍、归还书籍、浏览书籍等功能。本章将讲解使用Visual Studio 2008开发图书管理系统(应用程序的名称为“LibraryManager”,数据库的名称为“LibraryManagerDB”,数据库版本为SQL Server 2005)的方法,主要介绍以下知识点。 系统总体设计,包括功能设计、操作流程图、数据库设计等。 管理功能模块实现,包括管理员登录、主窗口、分类管理、书籍管理、借阅书籍等功能。 学生或教师功能模块实现,包括学生或教师登录、主窗口、归还书籍、浏览书籍等功能。
25.1 系统总体设计 本小节介绍图书管理系统——LibraryManager应用程序的总体设计,主要包括系统功能设计、操作流程图设计、图书管理系统应用程序的组成、LibraryManagerDB数据库设计、数据库实体类设计、应用程序主入口、应用程序全局变量等。
25.1.1 系统功能设计 图书管理系统可以分为两部分:管理员功能模块和学生或老师功能模块。管理员功能模块为管理员提供服务,它提供的功能如下,操作流程如图25.1所示。
25.1.2 图书管理系统组成 图书管理系统应用程序的名称为“LibraryManager”。在Visual Studio 2008的“解决方案资源管理器”面板中查看LibraryManager应用程序,如图25.3所示。LibraryManager应用程序的组成元素说明如下。
25.1.3 数据库设计 图书管理系统使用名称为“LibraryManagerDB”的Microsoft SQL Server 2005数据库,它包括6个表:Category、Group、User、Book、BookCategory和UserBook表。 1.Category表 2.Group表 3.User表 4.Book表 5.BookCategory表 6.UserBook表
25.1.4 数据库实体类设计 图书管理系统为LibraryManagerDB数据库创建名称为“LibraryManagerDB.dbml”的DBML文件,并把LibraryManagerDB数据库所有的表(Category、Group、User、Book、BookCategory和UserBook表)添加到该文件中,如图25.4所示。
25.1.5 应用程序主入口 应用程序主入口的程序代码位于Program.cs文件(保存在LibraryManage目录下)中。该文件定义名称为Program的静态类和static void Main()静态方法。该静态方法调用Application类的Run()静态方法运行第一个窗口——登录窗体(即LoginForm类的实例)
25.1.6 应用程序全局变量 图书管理系统在LibrarySystem.cs文件中创建了LibrarySystem类,并定义了一个全局的、静态的变量UserID。该变量用来保存登录用户的ID值。
25.2 管理员模块实现 管理员功能模块共包括登录、主窗口、分类管理、书籍管理、借阅书籍、查看借阅人等功能。管理员都能够通过主窗口查看和浏览所有书籍,以及书籍的借阅情况;借阅书籍窗口可以实现借阅书籍的功能,查看借阅人窗口可以查看某一个书籍的所有借阅人的信息。本小节介绍这些功能模块木咛迨迪帧
25.2.1 管理员登录 管理员登录功能由LoginForm.cs窗体(保存在LibraryManager目录下)实现。管理员可以输入用户名和密码,单击“登录”按钮实现登录功能,单击“取消”按钮关闭该窗口。
25.2.2 主窗口 管理员主窗口由MainForm.cs窗体(保存在LibraryManager目录下)实现。该窗口以列表形式显示指定分类下的书籍;管理员单击“分类管理”图标打开分类管理的窗口,单击“添加新书籍”按钮可以打开书籍管理窗口,单击“借阅书籍”按钮打开借阅书籍的窗口。
25.2.3 分类管理 分类管理功能由CategoryForm.cs窗体(保存在LibraryManager/Admin目录下)实现。管理员可以创建和维护书籍的分类树,如添加新的分类、修改分类名称、删除分类等。
25.2.4 书籍管理 书籍管理功能由BookForm.cs窗体(保存在LibraryManager/Admin目录下)实现。管理员可以输入用户名和密码,单击“登录”按钮实现登录功能,单击“取消”按钮关闭该窗口。
25.2.5 借阅书籍 借阅书籍功能由LendForm.cs窗体(保存在LibraryManager目录下)实现。该窗体实现借阅指定书籍给指定用户的功能。管理员可以选择借阅书籍的用户。
25.2.6 查看借阅人 查看借阅人功能由LendUserInfoForm.cs窗体(保存在LibraryManager目录下)实现。该窗口可以以列表方式显示指定书籍的所有借阅人的信息。
25.3 学生和老师功能模块实现 学生和老师功能模块共包括登录、主窗口、归还书籍、查看书籍信息、浏览书籍、借阅书籍等功能。学生和老师都能够通过主窗口查看其所借阅的书籍,并能够归还书籍;浏览书籍窗口可以根据书籍分类浏览各种书籍,并借阅书籍。本小节介绍这些功能模块的具体实现。
25.3.1 学生或老师登录 学生或老师登录功能也是由LoginForm.cs窗体(保存在LibraryManager目录下)实现。学生或老师也可以输入用户名和密码,单击“登录”按钮实现登录功能,单击“取消”按钮关闭该窗口。由于已经在25.2.1小节介绍了该窗体的实现,因此,在此不做详细介绍。
25.3.2 主窗口 学生和老师角色的主窗口都为由UserForm.cs窗体(保存在LibraryManager目录下)实现。该窗口以列表形式显示学生或老师已借的所有书籍;学生或老师单击“归还书籍”按钮可以归还选择的书籍;单击“浏览书籍”按钮可以打开浏览书籍的窗口。
25.3.3 归还书籍 当用户单击UserForm.cs窗体中的“归还书籍”按钮(btnReturn控件)触发Click事件——btnReturn_Click(object sender, EventArgs e)。该事件实现归还书籍的功能。
25.3.4 查看书籍信息 查看书籍信息功能由BookInfoForm.cs窗体(保存在LibraryManager目录下)实现。该窗口可以显示指定书籍的详细信息,如名称、作者、ISBN、出版单位、出版时间、数量、状态、电子文档、封面图片、图书简介、图书分类等。
25.3.5 浏览书籍 浏览书籍功能由BrowserForm.cs窗体(保存在LibraryManager目录下)实现。该窗口根据分类、以列表形式显示书籍信息,单击“借阅”链接可以借阅当前行表示的书籍。
25.3.6 借阅书籍 当用户单击“浏览书籍”窗口(BrowserForm.cs窗体)中每一行中的“借阅”链接时,可以实现借阅该行表示的书籍。该功能的实现方式和25.2.5小节中借阅书籍功能相似,因此,在此不做详细介绍。
25.4 小结 本章主要介绍了使用C#语言在Visual Studio 2008集成开发环境中开发图书管理系统的方法,主要包括功能设计、操作流程图、数据库设计,以及管理员登录、主窗口、分类管理、书籍管理、借阅书籍、学生或教师登录、主窗口、归还书籍、浏览书籍等功能的开发方法。其中,读者要着重掌握使用Windows窗体编程的方法,为后续编功能强大的Windows应用程序奠定基础。下一章将要介绍P2P(点对点)聊天程序。
25.5 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_25”的Windows应用程序,并在该应用程序中实现用户管理功能。
第26章 P2P聊天工具 P2P聊天工具是当前最为流行的点对点的聊天工具,它一般包括聊天工具的服务器、聊天工具的客户端等功能模块。本章将讲解使用Visual Studio 2008集成开发环境开发P2P聊天工具(名称为“P2PTalk”)的方法,主要介绍以下知识点。 系统总体设计,包括功能设计、P2P聊天工具组成等; P2P聊天工具类库实现; P2P聊天工具服务器聊天窗口实现; P2P聊天工具客户端聊天窗体实现。
26.1 系统总体设计 本小节介绍P2P聊天工具——P2PTalk项目的总体设计,主要包括系统功能设计、P2P聊天工具的组成等。
26.1.1 系统功能设计 P2P聊天工具可以分为两部分:P2P聊天工具客户端部分功能模块和P2P聊天工具服务器端部分功能模块。P2P聊天工具的客户端部分和服务器端部分功能模块都实现相同的功能,具体描述如下。 连接服务器,连接到指定的聊天服务器。 断开服务器的连接,断开已经连接的聊天服务器。 退出聊天,退出聊天状态,并释放占有的资源。 发送聊天消息,可以将消息发送到服务器。
26.1.2 P2P聊天工具组成 P2P聊天工具项目的名称为“P2PTalk”。在Visual Studio 2008的“解决方案资源管理器”面板中查看P2PTalk项目,如图26.1所示。P2PTalk项目包括3个应用程序,具体说明如下。 Client应用程序,P2P聊天工具的客户端应用程序。 P2PTalkLibrary类库,P2P聊天工具的类库,封装了实现聊天功能的类。 Server应用程序,P2P聊天工具的服务器端应用程序。
26.2 P2P聊天工具类库实现 P2P聊天工具类库由P2PTalkLibrary项目实现,该项目的类型为C#类库。如果生成该项目成功,将创建一个名称为“P2PTalkLibrary.dll”的动态链接库文件(保存在该项目的bin目录下)。 P2PTalkLibrary项目包括两个类文件:P2P.cs和Tool.cs,它们分别包含P2P类和Tool类。下面将详细介绍这两个类的功能。
26.2.1 Tool类 Tool类被包含在P2PTalk.Component命名空间中,并引用了2个命名空间:System.Net和System.IO。
26.2.2 P2P类 P2P类被包含在P2PTalk.Component命名空间中,并引用了2个命名空间:System.Net和System.IO。
26.3 P2P聊天工具服务器聊天窗口 P2P聊天工具服务器由Server项目实现,P2P聊天工具服务器聊天窗口由该项目下的MainForm.cs窗体(保存在P2PTalk目录下)实现。用户可以通过该窗口连接服务器,并和其他用户进行聊天。用户单击“连接”按钮可以连接到指定的服务器,单击“断开”按钮可以断开服务器的连接,单击“退出”按钮可以结束当前聊天状态,单击“发送”按钮可以将详细发送给其他在线用户。
26.4 P2P聊天工具客户端聊天窗口 由于P2P聊天工具客户端聊天窗口和P2P聊天工具服务器聊天窗口功能上非常相似,实现方法也比较相似。因此,在此不做详细介绍。
26.5 小结 本章主要介绍了使用C#语言在Visual Studio 2008集成开发环境中开发P2P聊天工具的方法,主要包括功能设计、P2P聊天工具组成,以及P2P聊天工具类库、P2P聊天工具服务器聊天窗口、P2P聊天工具客户端聊天窗体等功能的开发方法。其中,读者要着重掌握P2P聊天工具类库和P2P聊天工具客户端聊天窗体的方法,为后续编功能强大的网络应用程序奠定基础。下一章将要介绍使用ASP.NET技术(C#)开发校内网的方法。
26.6 习题 在Server应用程序(26.3小节)中添加用户管理功能,并实现可以将指定的消息仅仅发送的指定的某一个用户个功能。
第27章 我的校内网 校内网是当前最为流行的交流网站之一,它一般包括登录、主页面、好友、相册、日志、聊天等功能。本章将讲解使用Visual Studio 2008集成开发环境开发校内网网站(名称为“MyXiaonei”,数据库的名称为“XiaoneiDB”,数据库版本为SQL Server 2005)的方法,主要介绍以下知识点。 系统总体设计,包括功能设计、数据库设计等。 常用功能模块实现,包括登录、主页面、好友、相册、日志等功能。
27.1 系统总体设计 本小节介绍校内网——MyXiaonei网站的总体设计,主要包括系统功能设计、MyXiaonei网站的组成、XiaoneiDB数据库设计、数据库实体类设计、标题模块、网站配置等。
27.1.1 系统功能设计 校内网网站比较复杂,在此,仅仅介绍常用的功能,主要包括登录、好友(浏览好友、添加好友等)、相册(浏览照片、上传照片等)、日志等功能,具体描述如下。 用户登录,验证用户的身份是否合法。 主页面,校内网网站的主页面。 我的好友,按照分类方式浏览好友。 添加好友,可以查询用户,并添加为好友。 我的相册,按照分类方式浏览照片。 上传照片,上传照片到服务器,并指定相应的分类。 我的日志,按照分类方式浏览日志。 添加日志,将新的日志添加到指定的分类下。
27.1.2 校内网组成 校内网网站的名称为“MyXiaonei”。在Visual Studio 2008的“解决方案资源管理器”面板中查看MyXiaonei网站,如图27.1所示。
27.1.3 数据库设计 校内网网站使用名称为“XiaoneiDB”的Microsoft SQL Server 2005数据库,它包括6个表:Category、Group、User、Book、BookCategory和UserBook表。 1.User表 2.Category表 3.Friend表 4.Log表 5.Photo表
27.1.4 数据库实体类设计 校内网网站为XiaoneiDB数据库创建名称为“XiaoneiDB.dbml”的DBML文件,并把XiaoneiDB数据库所有的表(User、Category、Friend、Log和Photo表)添加到该文件中,如图27.2所示。
27.1.5 标题模块 标题模块由TitleUC.ascx用户控件实现,它将用来显示标题。
27.1.6 配置文件Web.config MyXiaonei网站的连接字符串放置在Web.config配置文件的<connectionString>元素中
27.2 常用功能模块实现 校内网网站的常用功能模块主要包括登录、好友(浏览好友、添加好友等)、相册(浏览照片、上传照片等)、日志等功能。本小节将介绍这些功能的具体实现方法。
27.2.1 登录页面 登录功能由Default.aspx页面实现,Default.aspx.cs文件为它的代码隐藏文件。该页面提供了输入用户名和密码的文本框,并实现用户登录的功能。Default.aspx页面的效果图如图27.3所示。 1.界面设计 2.事件设计
27.2.2 主页面 校内网主页面由Main.aspx和LeftTree.aspx页面共同实现。Main.aspx页面使用了框架,并放置了两个<frame>元素,它们的name属性的值分别为:Left和Desktop。其中,Left框架放置LeftTree.aspx页面,Desktop框架默认放置MyFriend.aspx页面。
27.2.3 我的好友 我的好友由MyFriend.aspx页面实现,MyFriend.aspx.cs文件为它的代码隐藏文件。该页面按照系统默认的分类显示当前登录用户的好友。MyFriend.aspx页面的效果图如图27.4所示。 1.界面设计 2.初始化 3.事件设计
27.2.4 添加好友 添加好友由AddFriend.aspx页面实现,AddFriend.aspx.cs文件为它的代码隐藏文件。该页面为考生提供选择考试科目的功能,并显示用户名称和考试时间。AddFriend.aspx页面的效果图如图27.5所示。 1.界面设计 2.初始化 3.事件设计
27.2.5 我的相册 我的相册由MyPhoto.aspx页面实现,MyPhoto.aspx.cs文件为它的代码隐藏文件。该页面按照系统默认的分类显示当前登录用户的照片。MyPhoto.aspx页面的效果图如图27.6所示。 1.界面设计 2.初始化 3.事件设计
27.2.6 上传照片 上传照片由UploadPhoto.aspx页面实现,UploadPhoto.aspx.cs文件为它的代码隐藏文件。该页面为用户提供上传照片的功能。其中,照片的文件保存到硬盘,照片的信息保存到数据库。UploadPhoto.aspx页面的效果图如图27.7所示。 1.界面设计 2.初始化 3.事件设计
27.2.7 我的日志 我的日志由MyLog.aspx页面实现,MyLog.aspx.cs文件为它的代码隐藏文件。该页面按照系统默认的分类显示当前登录用户的日志。MyLog.aspx页面的效果图如图27.8所示。 1.界面设计 2.初始化 3.事件设计
27.2.8 添加日志 添加日志由AddLog.aspx页面实现,AddLog.aspx.cs文件为它的代码隐藏文件。该页面为考生提供输入日志标题和内容,并提交到数据库的功能。AddLog.aspx页面的效果图如图27.9所示。 1.界面设计 2.初始化 3.事件设计
27.3 小结 本章主要介绍了使用C#语言在Visual Studio 2008集成开发环境中开发校内网的方法,主要包括统总体设计,包括功能设计、数据库设计,以及登录、主页面、好友、相册、日志、聊天等功能的开发方法。其中,读者要着重掌握使用Web窗体编程的方法,为后续编功能强大的ASP.NET网站奠定基础。
27.4 习题 在Visual Studio 2008集成开发环境中创建名称为“Test_27”的ASP.NET网站,并在该网站中实现用户管理功能。