描述
开 本: 32开纸 张: 胶版纸包 装: 平装-胶订是否套装: 否国际标准书号ISBN: 9787302466864
全书分4篇17章。程序基础篇(第1~4章)以控制台应用程序为主,介绍变量、常数基本数据类型的使用、流程控制的条件选择和循环以及数组和字符串等。对象使用篇(第5~9章)以面向对象为基础来探讨类和对象,提供对象“生命周期”的构造函数;探讨面向对象程序设计的三大特性,即继承、封装和多态;了解集合的特性等。窗口接口篇(第10~14章)以Windows Form为主,使用工具箱加入控件,包括显示信息的控件、文字编辑控件、具有选择功能的控件、提供互动的控件,以及键盘和鼠标事件的处理等内容。应用篇(第15~17章)介绍ADO.NET组件、LINQ语言的应用以及简易方块游戏的制作。
本书对Visual C#语言进行了全面的介绍,非常适合对Visual C#语言感兴趣、想对.NET Framework类库有更多认识的读者阅读。
目 录
第1篇 程序基础
第1章 欢迎来到C#的世界 1
1.1 从.NET Framework说起 2
1.1.1 公共语言运行库 2
1.1.2 .NET Framework类库 3
1.1.3 程序的编译 3
1.2 认识Visual Studio 2013 3
1.2.1 Visual Studio 2013的版本 4
1.2.2 启动软件并创建项目 4
1.2.3 “解决方案资源管理器”窗口 7
1.2.4 项目的打开和关闭 9
1.2.5 操作环境的设置 10
1.3 控制台应用程序 12
1.3.1 认识C#语言 12
1.3.2 程序语句 12
1.3.3 认识命名空间 13
1.3.4 编写程序代码 14
1.3.5 为程序代码加注释 15
1.3.6 让程序适时缩排 16
1.3.7 善用IntelliSense 17
1.3.8 创建并运行程序 18
1.4 重点整理 18
1.5 课后习题 19
第2章 数据与变量 21
2.1 什么是通用类型系统 22
2.1.1 整数类型 22
2.1.2 浮点类型和货币 23
2.1.3 其他数据类型 23
2.2 变量和常数 24
2.2.1 标识符的命名规则 24
2.2.2 关键字 24
2.2.3 声明变量 25
2.2.4 常数 27
2.2.5 枚举类型 29
2.3 控制台应用程序的输入输出语句 31
2.3.1 读取数据 31
2.3.2 输出数据 32
2.3.3 格式化输出 33
2.4 类型转换 34
2.4.1 隐式类型转换 35
2.4.2 显式类型转换 36
2.4.3 用户自定义类型——结构 38
2.5 运算符 40
2.5.1 算术运算符 40
2.5.2 赋值运算符 40
2.5.3 关系运算符 41
2.5.4 逻辑运算符 41
2.5.5 运算符的优先级 42
2.6 重点整理 42
2.7 课后习题 43
第3章 流程控制 46
3.1 认识结构化程序 47
3.2 条件选择 47
3.2.1 单一选择 48
3.2.2 双重选择 50
3.2.3 嵌套if 52
3.2.4 多重条件 55
3.3 循环 59
3.3.1 for循环 59
3.3.2 while循环 62
3.3.3 do/while循环 64
3.3.4 嵌套for 66
3.3.5 其他语句 67
3.4 重点整理 68
3.5 课后习题 69
第4章 数组和字符串 73
4.1 数组 74
4.1.1 一维数组的声明 74
4.1.2 数组元素的存取 76
4.1.3 数组的属性和方法 77
4.2 使用多维数组 81
4.2.1 创建二维数组 81
4.2.2 二维数组初始化 82
4.2.3 不规则数组 84
4.2.4 隐式类型数组 86
4.3 字符和字符串 87
4.3.1 转义字符 87
4.3.2 创建字符串 88
4.3.3 字符串常用方法 89
4.3.4 使用StringBuilder类 93
4.4 重点整理 96
4.5 课后习题 97
第2篇 对象使用
第5章 对象和类 101
5.1 面向对象的基础 102
5.1.1 认识对象 102
5.1.2 提供蓝图的类 102
5.1.3 抽象化概念 103
5.2 使用类 104
5.2.1 定义类 104
5.2.2 实例化对象 105
5.2.3 访问权限 106
5.2.4 定义方法成员 107
5.2.5 类属性和存取器 109
5.3 对象旅程 113
5.3.1 产生构造函数 114
5.3.2 析构函数回收资源 115
5.3.3 使用默认构造函数 116
5.3.4 构造函数的重载 118
5.3.5 对象的初始设置 119
5.4 静态类 121
5.4.1 认识静态类成员 121
5.4.2 静态属性 121
5.4.3 静态类方法 122
5.4.4 静态构造函数 124
5.5 重点整理 126
5.6 课后习题 127
第6章 方法和传递机制 130
6.1 方法是什么 131
6.1.1 系统内建的方法 131
6.1.2 方法的声明 133
6.2 参数的传递机制 137
6.2.1 传值调用 137
6.2.2 传址调用 139
6.3 方法的传递对象 141
6.3.1 以对象为传递目标 141
6.3.2 参数params 142
6.3.3 关键字ref和out的不同 143
6.3.4 更具弹性的命名参数 145
6.3.5 能选择的选择性参数 146
6.4 方法的重载 147
6.5 了解变量的作用域 149
6.6 重点整理 151
6.7 课后习题 152
第7章 继承、多态和接口 155
7.1 了解继承 156
7.1.1 特化和泛化 156
7.1.2 组合关系 157
7.1.3 为什么要有继承机制 157
7.2 单一继承机制 157
7.2.1 继承的存取(或访问) 158
7.2.2 访问权限修饰词protected 162
7.2.3 调用基类成员 165
7.2.4 隐藏基类成员 170
7.3 探讨多态 174
7.3.1 父、子类产生方法重载 174
7.3.2 覆盖基类 175
7.3.3 实现多态 177
7.4 接口和抽象类 181
7.4.1 定义抽象类 181
7.4.2 认识密封类 184
7.4.3 接口的声明 184
7.4.4 如何实现接口 186
7.4.5 实现多个接口 188
7.4.6 接口实现多态 190
7.5 重点整理 192
7.6 课后习题 193
第8章 泛型和集合 196
8.1 浅谈集合 197
8.1.1 认识索引键/值 197
8.1.2 使用下标 204
8.1.3 顺序访问集合 206
8.2 创建泛型 208
8.2.1 为什么使用泛型 208
8.2.2 定义泛型 210
8.2.3 产生泛型方法 210
8.3 委托 212
8.4 重点整理 215
8.5 课后习题 216
第9章 错误和异常处理 218
9.1 Visual Studio调试环境 219
9.1.1 错误列表窗口 219
9.1.2 如何调试 220
9.1.3 进入调试程序 223
9.1.4 加入断点 225
9.2 常见的错误 228
9.2.1 语法错误 228
9.2.2 逻辑错误 229
9.3 异常情况的处理 230
9.3.1 认识Exception类 230
9.3.2 简易的异常处理 231
9.3.3 Finally程序块 233
9.3.4 使用throw抛出错误 235
9.4 重点整理 236
9.5 课后习题 237
第3篇 窗口接口
第10章 窗口窗体的运行 239
10.1 Windows 窗体的基本操作 240
10.1.1 创建Windows 窗体项目 240
10.1.2 Windows 窗体的工作环境 241
10.1.3 创建用户界面 245
10.1.4 编写程序代码 250
10.1.5 程序存储的位置 253
10.2 Windows 窗体的运行 254
10.2.1 部分类是什么 254
10.2.2 Main()主程序在哪里 255
10.2.3 消息循环 256
10.2.4 在程序中设置属性 257
10.3 使用窗体 260
10.3.1 窗体的属性和方法 260
10.3.2 窗体的事件 262
10.4 MessageBox类 265
10.4.1 显示消息 265
10.4.2 按钮的枚举成员 265
10.4.3 图标的枚举成员 266
10.4.4 DialogResult如何接收 266
10.5 重点整理 270
10.6 课后习题 271
第11章 公共控件 274
11.1 显示信息 275
11.1.1 标签控件 275
11.1.2 超链接控件 280
11.1.3 进度条控件 285
11.1.4 状态栏和面板 285
11.1.5 计时的Timer控件 287
11.1.6 窗体上控件的顺序 290
11.2 文字编辑 292
11.2.1 TextBox控件 292
11.2.2 RichTextBox控件 299
11.2.3 MaskedTextBox控件 307
11.3 与日期有关的控件 308
11.3.1 MonthCalendar控件 308
11.3.2 DateTimePicker控件 314
11.4 具有选择功能的控件 316
11.4.1 单选按钮 316
11.4.2 复选框 321
11.4.3 下拉列表框 321
11.4.4 列表框 327
11.4.5 CheckedListBox控件 328
11.5 重点整理 331
11.6 课后习题 332
第12章 提供互动的控件 337
12.1 文件对话框 338
12.1.1 OpenFileDialog控件 338
12.1.2 SaveFileDialog控件 340
12.1.3 FolderBrowserDialog控件 344
12.2 设置字体与颜色 348
12.2.1 FontDialog控件 349
12.2.2 ColorDialog控件 349
12.3 支持打印的组件 353
12.3.1 PrintDocument控件 353
12.3.2 PrintDialog控件 358
12.3.3 PrintPreviewDialog控件 359
12.3.4 PageSetupDialog控件 363
12.4 菜单 364
12.4.1 MenuStrip控件 365
12.4.2 ContextMenu控件 376
12.4.3 ToolStrip控件 378
12.5 重点整理 380
12.6 课后习题 381
第13章 多文档界面和版面布局 385
13.1 多文档界面 386
13.1.1 认识多文档界面 386
13.1.2 MDI窗体的成员 388
13.1.3 窗体的排列 389
13.2 版面布局 390
13.2.1 FlowLayoutPanel控件 390
13.2.2 TableLayoutPanel控件 392
13.2.3 SplitContainer控件 395
13.3 具有查看功能的控件 395
13.3.1 ImageList控件 395
13.3.2 ListView控件 400
13.3.3 TreeView控件 410
13.4 键盘和鼠标事件 415
13.4.1 认识键盘事件 415
13.4.2 KeyDown和KeyUp事件 415
13.4.3 KeyPress事件 419
13.4.4 认识鼠标事件 420
13.4.5 获取鼠标信息 421
13.4.6 鼠标的拖曳功能 423
13.5 重点整理 426
13.6 课后习题 427
第14章 I/O与数据流处理 431
14.1 数据流与System.IO 432
14.2 文件与数据流 432
14.2.1 文件目录 433
14.2.2 文件信息 438
14.2.3 使用File静态类 441
14.3 标准数据流 445
14.3.1 FileStream类 446
14.3.2 StreamWriter写入器 449
14.3.3 StreamReader读取器 449
14.4 重点整理 452
14.5 课后习题 452
第4篇 应用
第15章 ADO.NET组件 455
15.1 数据库基础 456
15.1.1 数据库系统 456
15.1.2 认识关系数据库 457
15.2 认识ADO.NET 457
15.2.1 System.Data命名空间 457
15.2.2 ADO.NET架构 458
15.3 获取数据源 459
15.3.1 生成DataSet 459
15.3.2 查看数据源窗口 464
15.3.3 DataGirdView控件 465
15.4 简易SQL语句 470
15.4.1 使用查询生成器 470
15.4.2 SELECT子句 478
15.4.3 WHERE子句 478
15.4.4 动态查询 479
15.5 用程序代码来提取、存入数据 481
15.5.1 导入相关命名空间 481
15.5.2 用Connection对象连接数据库 482
15.5.3 用Command对象执行SQL语句 483
15.5.4 DataReader显示内容 484
15.5.5 DataAdapter载入数据 486
15.6 重点整理 488
15.7 课后习题 490
第16章 语言集成查询——LINQ 494
16.1 LINQ简介 495
16.2 基本的LINQ语法 495
16.2.1 获取数据源 495
16.2.2 创建查询 496
16.2.3 执行查询 496
16.2.4 配合orderby和group子句 498
16.3 LINQ的应用 500
16.3.1 LINQ to Object 500
16.3.2 LINQ to SQL 502
16.4 重点整理 507
16.5 课后习题 508
第17章 简易方块游戏 510
17.1 图形设备接口 511
17.1.1 窗体的坐标系统 511
17.1.2 产生画布 512
17.2 绘制图形 513
17.2.1 认识Graphics类 513
17.2.2 配合画笔绘制线条、几何图形 514
17.2.3 绘制字体 516
17.2.4 Color结构 518
17.3 简易方块游戏 519
17.3.1 游戏界面说明 520
17.3.2 方块的版面 521
17.3.3 方块的组成和移动 521
17.3.4 简易方块游戏相关信息 523
下载资源获取为了方便读者学习,本书给出了完整的范例程序代码,可从以下地址(注意区分数字和英文字母大小写)下载:
http://pan.baidu.com/s/1i59ds5f
如果下载有问题,请发送电子邮件至[email protected],邮件主题设置为“求Visual C# 2013从零开始学下载资源”。
编 者2017年4月
章节重点? 泛型(Generics)类具有重复使用性、类型安全和高效率的优点。? 认识配对集合“索引键(key)/值(value)” 。? 能把方法当作变量进行传递的委托。8.1 浅谈集合一般而言,“集合”可视为对象容器,用于群组和管理相关的对象。例如,每个Windows 窗体都是一个控件集合,用户可用窗体的Controls进行存取。我们已经学习过数组,乍看之下,集合的结构和数组非常相似(可将数组视为集合的一种),有下标,也能通过For Each…Next循环来读取集合中的各表项。一般来说,数组的下标是静态的,经过声明后,数组中的元素不能被删除,若因实际需求要再插入一个数组元素,则只能将数组重新清空,或重设数组大小。为了让索引和表项的处理更具弹性,.NET Framework通过“System.Collections”命名空间提供了集合类和接口,下面以表8-1来说明。表8-1 System.CollectionCollections(集合) 说 明ICollection接口 定义所有非泛型集合的大小、枚举值和同步方法IDictionary接口 非泛型集合的索引键/值组IDictionaryEnumerator接口 枚举非泛型字典的元素IEnumerable接口 公开逐一查看非泛型集合的枚举值IList接口 由下标存取对象的非泛型集合DictionaryEntry结构 定义可设置或提取的字典索引键/值组配对ArrayList类 按数组大小动态增加,实现IList接口Hashtable类 根据索引键的哈希程序代码组织而成的索引键/值组集合Queue类 对象的先进先出(FIFO)集合SortedList类 索引键/值组配对的集合,按索引键排序Stack类 简单非泛型集合,对象组成的后进先出(LIFO)集合使用集合时,其表项会有变动,并且要存取这些集合时必须通过“下标”(index)来确定表项。一般而言,下标通常以“0”为起始值。将表项存入集合时,还可以使用对象类型的索引键(key)提取所对应的值(value)。当集合中没有下标或索引键时,必须按序提取表项,例如使用Queue类或Stack类。8.1.1 认识索引键/值“索引键(key)/值(value)”是配对的集合,值存入时可以指定对象类型的索引键,以便于使用索引键来提取对应的值。命名空间“System.Collections”中的Hashtable、SortedList等都是提供索引键/值配对的类。使用非泛型来枚举元素进行配对时,可以使用IDictionary、IDictionaryEnumerator接口。先以IDictionary来了解索引“键/值”存取对象的方法,请参考表8-2。表8-2 IDictionary接口成员IDictionary成员 说 明Count 获取ICollection项数Items 获取或设置索引键的指定表项Keys 集合中所有表项的索引键Values 集合中所有表项的值Add()方法 将表项加入集合中,须使用key/value配对Clear()方法 将集合中所有表项删除Contains()方法 查询指定表项的key,返回Boolean类型CopyTo()方法 从特定的Array索引开始,复制ICollection 表项至ArrayGetEnumerator() 返回IDictionary对象的IDictionaryEnumerator对象Remove()方法 从集合中删除指定的表项IDictionary接口是索引键/值组非泛型集合的基类接口,泛型版本就是位于“System. Collections.Generic”命名空间的IDictionary。IDictionaryEnumerator接口能处理枚举非泛型字典的元素,相关成员如表8-3所示。表8-3 IDictionaryEnumerator成员IDictionaryEnumerator成员 说 明Current 获取集合中当前的表项Entry 获取当前字典表项的索引键和值Key 获取当前字典表项的索引键Value 获取当前字典表项的值MoveNext() 将枚举值往前推至集合中的下一个表项Reset()方法 设置枚举值至初始位置,即集合个元素(表项)前一般来说,实现IDictionary接口就是要实现表8-2定义的方法。下面以一个简单的查询概念来解说。 1 导入命名空间“System.Collections”。using System.Collections; 2 创建一个实现IDictionary接口的类,例如Lexicon类。Public Class Lexicon : IDictionary{ //程序段} 3 将索引键/值组配对,在构造函数中使用DictionaryEntry结构来指定索引键(key)/值(value)配对。延续上述例子,自行定义构造函数。//以数组来处理索引键/值的配对private DictionaryEntry[] article;private Int32 ItemsInUse = 0;// 构造函数 —— 以DictionaryEntry结构来指定配对public Lexicon(Int32 manyItems) { article = new DictionaryEntry[manyItems];} 4 实现IDictionary接口的属性和方法。以items属性来说,语法如下:Object this[Object key] { get; set; }● key:要获取或设置的表项的索引键。该语句表示实现接口items属性时,存取器get和set都要实现。public object this[object key]{ get { //判断下标值是否在字典中,若有,则返回其值 Int32 index; if (IndexOfKeyDoWork(key, out index)) { //找到索引键,返回其值 return article[index].Value; } else { //没有找到索引键 return null; } } set { //判断下标值是否在字典中,若有,则更换其值 Int32 index; if (IndexOfKeyDoWork(key, out index)) { article[index].Value = value; } else { //字典中没有发现,以新增方式将索引键/值配对 Add(key, value); } }} 5 同样,实现Add()方法后才能创建Lexicon对象。这里以Add方法加入“索引键/值”,使用Add()方法将带有索引键和值的表项加入IDictionary对象,语法如下:void Add(Object key, Object value)● key:要加入表项的索引键。● value:要加入表项的值。//先实现Add()方法public void Add(object key, object value){ //如果索引键已经存在,就以新增方式将索引键/值配对 if (useFreg == article.Length) { throw new InvalidOperationException(“无法再新建项目”); } article[useFreg ] = new DictionaryEntry(key, value);}//再以Add()方法加入表项IDictionary lex = new Lexicon(5);lex.Add(“Tomas”, 25);lex.Add(“Michelle”, 27);使用“索引键/值”,再加上下标(index),其数据结构如图8-1所示。 图8-1 索引键/值的结构由于使用的是DictionaryEntry结构,因此可使用foreach循环来读取表项。foreach(DictionaryEntry de in lex) lblShow.Text = String.Format(“{0}, 年龄 : {1}”, _ de.Key, de.Value);DictionaryEntry的对象会存储每个表项的索引键/值组,且每个配对必须具有名称。IDictionary接口允许列举所包含的索引键和值,但是不表示任何特定的排列顺序。通常IDictionary接口实现分为3类:只读、固定大小、可变大小。● 只读:IDictionary对象无法修改。● 固定大小:IDictionary对象不允许加入或删除表项,但允许修改现有表项。● 可变大小:IDictionary对象允许加入、删除和修改表项。 CH0801A IDictionary接口的Key和Value 1 模板为“控制台应用程序”,项目名称为“CH0801A.csproj”。在该项目下加入两个类:Lexion(实现IDictionary接口)和enumLexicom(实现IDictionaryEnumerator接口)。Program.cs是Main()主程序所在的文件。 2 在“Lexion.cs”中编写的程序代码如下:14 class Lexion : IDictionary15 {16 //以数组来处理索引键/值的配对17 public DictionaryEntry[] article;18 protected Int32 useFreg = 0;19 //构造函数 —— 以DictionaryEntry 结构来指定配对值20 public Lexion(Int32 manyItems)21 {22 article = new DictionaryEntry[manyItems];23 }24 //删除指定表项25 public void Remove(object key)26 {27 if (key == null)28 {29 throw new ArgumentNullException(“key”);30 }31 //尝试从DictionaryEntry数组中寻找索引键(key)32 Int32 index;33 if (IndexOfKeyDoWork(key, out index))34 {35 //如果找到了,就让所有表项向上移动36 Array.Copy(article, index 1, article, index,37 useFreg – index – 1);38 useFreg–;39 }40 else //即使没有,也要返回结果41 Console.WriteLine(“找不到要删除的名称”);42 }43 …//省略程序代码44 } 3 在“enumLexicom.cs”中编写的程序代码如下:13 class enumLexicom : IDictionaryEnumerator14 {15 //IDictionaryEnumerator枚举非泛型字典的元素16 DictionaryEntry[] article;17 Int32 index = -1;18 //构造函数19 public enumLexicom(Lexion lc)20 {21 article = new DictionaryEntry[lc.Count];22 //以复制方式将Lexicon对象的索引键/值配对23 Array.Copy(lc.article, 0, article, 0, lc.Count);24 }25 //返回当前的表项26 public Object Current27 {28 get{VerityEnumIndex(); return article[index];}29 }30 //返回当前字典表项的索引键/值31 public DictionaryEntry Entry32 {33 get{return (DictionaryEntry)Current;}34 }35 …//省略程序代码36 } 4 在Main()主程序中编写的程序代码如下:11 static void Main(string[] args)12 {13 int peop = 4;14 //根据IDictionary接口实现类Lexion所创建的对象15 IDictionary lex = new Lexion(peop);16 //以Add新增4位成员17 while(peop >= 1)18 {19 Console.Write(“输入名字:”);20 string title = Console.ReadLine();21 Console.Write(“输入分数:”);22 int score = int.Parse(Console.ReadLine());23 lex.Add(title, score);24 peop–;25 }26 Console.WriteLine(“学生人数 = {0}” , lex.Count);27 Console.WriteLine(“Matthew是否为学生?{0}, 分数 : {1} ” , 28 lex.Contains(“Matthew”), lex[“Matthew”]);29 //显示索引键/值配对30 foreach (DictionaryEntry de in lex)31 {32 Console.WriteLine(“{0}, 分数 : {1}”, 33 de.Key, de.Value);34 } 35 //删除某个表项36 lex.Remove(“Naomi”);37 //显示学生名称(索引键)38 foreach(string title in lex.Keys)39 Console.Write(“{0} “, title); 40 //显示学生年龄41 foreach(int score in lex.Values)42 Console.Write(“{0,3}”, score);43 }运行:按“Ctrl F5”组合键运行程序,打开“命令提示符”窗口,按提示输入名字和分数,显示图8-2所示的运行结果。程序说明? 创建一个简易的查询表,以Lexion类实现IDictionary接口创建查询表,以enumLexicom类实现IDictionaryEnumerator接口维护查询表的正确性。Lexion.cs程序(实现IDictionary接口)? 第26~42行:Lexion类实现Remove()方法,根据索引键(key)删除指定表项。? 第27~30行:如果找不到指定的表项会以throw语句抛出异常。? 第33~41行:如果找到表项并删除了,就以Array类的Copy()方法把表项向上移动。enumLexicom.cs程序(实现IDictionaryEnumerator接口)? 第19~24行:构造函数。当查询表有变动时,配合Array类的Copy()方法来重新创建一个查询表。? 第26~29行:属性Current按下标值来获取当前的表项。? 第31~34行:属性Entry按Current返回值读取当前表项的索引键/值。Main()主程序? 第15行:根据IDictionary接口实现类Lexion所创建的lex对象。? 第17~25行:以while循环来创建名字分数的数据,再以Add()方法加入查询表中。? 第26~28行:以属性Count来统计输入学生数,Contains来对比指定表项“Matthew”,若查询到,则返回True结果以及Matthew的分数。? 第30~34行:使用DictionaryEntry结构,并以foreach循环来读取输入的索引键/值。? 第36~42行:以Remove方法来删除指定表项,再重新读取学生的名字和分数。8.1.2 使用下标使用集合表项避免不了新增和删除,这些集合表项的存取就得使用下标(index)。“下标”是介于0或1和集合表项数目之间的整数。通过命名空间“System.Collections”的IList接口可以了解以下标存取对象的属性和方法,可参考表8-4。表8-4 IList接口的成员IList接口成员 说 明Count 获取集合表项数Item 获取或设置集合表项IsFixedSize 集合是否为固定大小IsReadOnly 集合是否为只读Add()方法 将表项加入集合中Clear()方法 将所有表项删除Contains()方法 查询的指定表项是否在集合中,返回Boolean类型IndexOf()方法 查询指定表项的下标值,返回Integer类型,-1表示不存在Insert()方法 将表项插入到指定的下标位置Remove方法 从集合中删除指定的表项RemoveAt() 从集合中删除指定下标值对应的表项ArrayList实现System.Collection的IList接口,会根据数组列表大小动态增加容量,提供新增、插入、删除元素的方法,比数组更具弹性。随着元素的逐渐加入,ArrayList会视需要重新配置可以保存的表项数。以构造函数来指定其容量的语句如下:ArrayLIst arrayList = new ArrayList[6];arrayList.Capacity[5];若要降低容量,则可调用TrimToSize或设置Capacity属性。由于ArrayList比Array更具弹性,因此使用时有所区别,可参照表8-5的说明。表8-5 Array和ArrayList的比较异 同 点 Array ArrayList使用类型时 声明时要指定类型 可以是任何对象能否扩充容量 自动扩充容量数组元素 不能动态改变 由Insert新增,由Remove删除性能 较好 比较差使用ArrayList类的Add()方法加入数据时会加到结尾处,而且允许加入不同类型的表项。ArrayList arrayList = new ArrayLIst();arrayList.Add(“Tomas”);arrayList.Add(25);arrayList.Add(false);ArrayList arrayList2 = new ArrayLIst {“Tomas”, 25, false}; CH0801B 使用ArrayList类 1 设置模板为“控制台应用程序、项目名称为“CH0801B.csproj”。 2 “Main()”主程序编写的程序代码如下:14 static void Main(string[] args)15 {16 ArrayList student = new ArrayList();17 DateTime date1 = new DateTime(1992, 3, 5);18 //以Add()方法加入表项19 student.Add(“Michelle”);20 student.Add(date1.ToShortDateString());21 student.Add(“Doris”);22 student.Add(33);23 itemPrint(“列出结果:”, student);24 //若有某个表项,则删除25 if (student.Contains(date1.ToShortDateString()))26 {27 student.Remove(date1.ToShortDateString());28 student.RemoveAt(2);//指定下标位置删除29 itemPrint(“经过删除后:”, student);30 }31 else32 itemPrint(“不存在!”, student);33 //新建表项34 Int32 index = 0;35 student.Insert(index, “Tomas”);36 student.Add(“Stephen”);37 itemPrint(“插入新表项:”, student);38 student.Sort();39 itemPrint(“经过排序:”, student);40 }41 //for循环读取表项42 public static void itemPrint(string str, 43 ArrayList arrList)44 {45 Int32 index = 0;46 Console.Write(“{0}”, str);47 foreach (Object obj in arrList)48 {49 Console.Write(“[{0}]-{1, -10}”, index, obj);50 index ;51 }52 Console.WriteLine();53 }运行:按“Ctrl F5”组合键运行此程序,打开“命令提示符”窗口,运行结果如图8-3所示。 图8-3 范例CH0801B的运行结果程序说明? 第16~22行:创建ArrayList类的对象student,以Add()方法加入类型不同的表项,调用itemPrint()方法传入参数值,显示结果。? 第25~32行:以if来判断要删除的表项是否存在。以Remove()指定表项,以RemoveAt()指定下标值位置进行删除。? 第35~38行:以Add()方法加入新表项,或者以Insert()指定下标位置加入表项,后以Sort()方法进行排序。? 第42~53行:itemPrint()方法接收参数值后,以foreach循环来读取表项内容并输出结果。8.1.3 顺序访问集合在集合表项中有两种处理数据的方式,即先进先出、后进先出。先进先出的Queue下面对其中的类Queue(队列)来做介绍。Queue采用FIFO(First In First Out,先进先出),也就是个加入的表项会个从集合中删除。Queue的属性和方法可参照表8-6的说明。表8-6 Queue类的成员Queue成员 说 明Count 获取队列的表项个数Clear() 从队列中删除所有对象Contains() 判断表项是否在队列中CopyTo() 指定数组下标,将表项复制到现有的一维Array(数组)中Dequeue() 返回队列前端的对象并删除(续表)Queue成员 说 明Enqueue() 将对象加入到队列末端Equals() 判断指定的对象和当前的对象是否相等Peek() 返回队列个对象TrimToSize() 设置队列中的实际表项个数队列处理数据的方式就如同排队买票一般,前面的人可以个购得票,等待在后的人必须等待前方的人购完票后才能购票。 CH0801C 使用Queue类 1 设置模板为“控制台应用程序”、项目名称为“CH0801C.csproj”。 2 在Main()主程序中编写的程序代码如下:14 static void Main(string[] args)15 {16 Int32 one, index = 6;17 //创建队列对象18 Queue fruit = new Queue();19 string[] name = {“Strawberry”, “Watermelon”, “Apple”,20 “Orange”, “Banana”, “Mango”};21 for (int ct = 0; ct < name.Length; ct )22 {23 fruit.Enqueue(name[ct]);//由末端加入元素24 }25 //Peek()方法显示种水果 26 if (fruit.Count > 0)27 {28 one = index – fruit.Count 1;29 Console.WriteLine(“第{0}种水果 – {1}”, one,30 fruit.Peek());31 }32 itemPrint(“水果”, fruit);33 //Dequeue()删除前端的表项34 if (fruit.Count > 0)35 {36 one = index – fruit.Count 1;37 Console.WriteLine(“删除第{0}种水果 – {1}”, one, 38 fruit.Dequeue());39 }40 itemPrint(“少了一种水果之后”, fruit);运行:按“Ctrl F5”组合键运行此程序,打开“命令提示符”窗口,运行结果如图8-4所示。程序说明? 创建Queue类的对象fruit,以Peek方法显示个表项,以Enqueue()方法将表项从尾端加入,以Dequeue()方法从前端删除表项。? 第18~24行:创建Queue对象fruit,并以for循环配合Enqueue()方法将数组name加到队列中。? 第26~31行:先以Count属性进行判断,如果表项存在,就以Peek()显示个表项。? 第34~39行:以Dequeue()方法删除个表项。后进先出的Stack可以将Stack(堆栈)类数据的进出想象成叠盘子,从底部向上堆叠,想要获取底部的盘子,只有从上方把后加进来的盘子拿走才有可能,这就形成了LIFO(Last In First Out,后进先出)的方式。先使用Push()方法将表项加到上方,再使用Pop()方法弹出(移除)上方的表项。Stack常用成员如表8-7所示。表8-7 Stack成员Stack成员 说 明Count 获取堆栈的表项个数Clear() 从堆栈中删除所有表项Peek() 返回堆栈上端的表项Push() 将表项加到堆栈的上方Pop() 将堆栈上方的表项删除8.2 创建泛型泛型类和方法将重复使用性、类型安全和高效率结合在一起,提供了非泛型的类和方法无法提供的功能。泛型常搭配的是集合类及其方法的使用。.NET Framework的类库提供了命名空间System.Collections.Generic,其中包含多个以泛型为基础的集合类。● 使用泛型以优化程序代码的重复使用性、类型安全性和高效率。● 泛型常见的用法是创建集合类。8.2.1 为什么使用泛型或许大家会很奇怪,为什么要使用泛型呢?下面以简单例子来说明。11 static void Main(string[] args)12 {13 int[] one ={11,12,13,14,15};//个数组14 string[] two = {“Eric”, “Andy”, “John”};//第二个数组15 ShowMessage1(one);//读取数组(一)16 ShowMessage2(two);//读取数组(二)17 }18 //读取数组(一)19 private static void ShowMessage1(int[] arrData)20 {21 foreach(int item in arrData)22 Console.Write(“{0, 3}”, item);23 Console.WriteLine(“n”);24 }25 //读取数组(二)26 private static void ShowMessage2(string[] arrData)27 {28 foreach(string item in arrData)29 Console.Write(“{0, 6}”, item);30 Console.WriteLine(“n”);31 }● 第13、14行:声明两个数组,类型不同,长度也不一样。● 第19~24行:foreach循环读取整数类型的数组。● 第26~31行:另一个foreach循环读取字符串类型的数组。● 问题:如果有更多不同类型的数组要处理,是不是要编写更多的程序代码呢?如果将ShowMessage()方法修改如下:19 //读取数组 —— 使用泛型20 private static void ShowMessage(T[] arrData)21 {22 foreach(T item in arrData)23 Console.Write(“{0} “, item);24 Console.WriteLine(“n”);25 }? 第20行:在ShowMessage()方法后加入(尖括号)内有类型参数T,用来取代原有的int或string类型,进一步来说,可以代表任何数据类型。? 第22行:以foreach循环读取时,原来的“int/string”类型就被T取代。当arrData接收的是int类型时,foreach循环就读取整数类型;当arrData数组接收的是string时,就以字符串来处理。如此一来,不管有多少数组,使用泛型的写法都会大大改进原有的问题,这也是泛型的魅力所在!8.2.2 定义泛型泛型能以未定类型的变量来声明类、接口或方法。使用new来实例化对象可以指定变量的类型。定义泛型后,不用为不同的变量类型编写相同的程序代码,可以提高类型安全,让不同的类型做相同的事,让对象彼此共享方法成员,达到重复使用性。双效合一后,能让程序的效率提高!定义泛型的语法如下:class 泛型名称 { //程序段}● 定义泛型以class开头,接着是泛型名称。● 尖括号内放入类型参数(Type parameter)列表,一般使用大写字母T来表示。● 尖括号内的每个变量代表一个数据类型名称,参数间以逗号隔开。● 定义泛型时,先使用类型参数进行声明,表示此类型数据是未定的。下面是一个简单的泛型语句。class GenericList //只有一个变量{ Console.WriteLine(“nRunning!”);}8.2.3 产生泛型方法定义泛型后要进一步定义公有的方法成员。以泛型类的成员来说,类型参数是声明泛型类型的变量,会以特定类型的替代符号(Placeholder)来指定,其后相关的数据都适用,声明方法如下:public void 方法名称(T 变量名称){ //程序段}实际的方法成员语句如下:public void ShowMessage(T output) Console.WriteLine(“n{0} is Running!”, output);}有了泛型和成员方法,就可以使用new运算符创建不同数据类型的实体对象了,语法 如下:泛型类名称 对象名称 = new 泛型类名称();延续前一个范例的概念,创建一个泛型类,可以输入string、int类型的数据来存放,再以foreach循环进行输出。 CH0802C 使用泛型类 1 设置模板为“控制台应用程序”、项目名称为“CH0802C.csproj”,再加入一个类Student.cs。 2 在“Student.cs”类中的程序代码如下:11 class Student12 {13 private int index;//数组下标值14 private T[] items = new T[5];//存储6个数组元素15 //将数据放入数组,string、int类型16 public void StoreArray(T arrData)17 {18 if (index < items.Length)19 {20 items[index] = arrData;21 index ;22 }23 }24 //读取数组元素25 public void ShowMessage()26 {27 foreach (T element in items)28 {29 Console.Write(“{0, 6} “, element);30 }31 Console.WriteLine(“n”);32 }33 } 3 在Main()主程序中编写的程序代码如下:11 static void Main(string[] args)12 {13 //创建泛型类对象 —— 学生名称14 Student manyStudent = new Student();15 manyStudent.StoreArray(“Tomas”);16 manyStudent.StoreArray(“John”);17 manyStudent.StoreArray(“Eric”);18 manyStudent.StoreArray(“Steven”);19 manyStudent.StoreArray(“Mark”);20 manyStudent.ShowMessage();21 //创建泛型类对象 —— 成绩22 Student Score = new Student();23 Score.StoreArray(78);24 Score.StoreArray(83);25 Score.StoreArray(48);26 Score.StoreArray(92);27 Score.StoreArray(65);28 Score.ShowMessage();29 }运行:按“Ctrl F5”键运行此程序,打开“命令提示符”窗口,运行结果如图8-5所示。 图8-5 范例CH0802C的运行结果程序说明Student.cs程序? 创建泛型类Student,含有T类型参数,以不同类型来创建数据。? 第14行:创建含有T类型参数的数组,可以存放6个元素。? 第16~23行:StoreArray()使用T类型参数来接收输入的数组元素,使用for循环来读取输入的数组元素。? 第25~33行:ShowMessage()方法以foreach循环来输出数组元素。Main()主程序? 第14行:以泛型类来创建一个对象,表示以字符串类型为主。? 第22行:以泛型类来创建一个对象,表示以整数类型为主。? 讨论:泛型类Student代表它不是真的类型,比较像是类型的蓝图。使用时必须借助尖括号来指定类型变量,让编译程序可以辨认它的类型。8.3 委 托当程序中调用方法时会进行变量的传递,它通常有所限制,只能使用常数、变量、对象或数组,但是方法无法以变量来传递!委托(Delegate)就是把“方法”视为变量来传递。委托是一种类型,代表具有特定参数列表和返回类型的方法引用。也就是在程序中调用方法时,可以将其实例通过委托实例执行(Invoke,或调用)方法。Windows窗体的控件触发的事件处理程序就是以委托方式来处理的,将方法当作变量传递给其他方法。委托类型派生自 .NET Framework中的Delegate类。委托类型是密封的,不能作为其他类型的派生来源,且不能从Delegate派生自定义类。因为实现的实例是委托对象,所以它可以作为参数传递或赋值给属性。如此一来,方法才能以参数方式接受委托,并进行委托的调用,这称为异步返回调用,是较长进程完成时通知调用端的常用方法。所以要定义委托时是以关键字delegate来声明一个方法,其语法如下:delegate 数据类型 委托名称(变量列表);● 委托名称:用来指定方法的委托名称。● 数据类型:参考方法的返回值类型。定义委托名称后,还要声明一个委托对象,用来传递方法。public delegate bool Speculation(Int32 numerical);Speculation evenPredicate;//声明委托变量evenPredicate = new Speculation(IsEven);//IsEven()方法后还要定义一个委托方法,将委托对象以变量来传递。private static List ArrayPercolate(int[] intArray, Speculation special){ . . . } CH0803 使用委托 1 设置模板为“控制台应用程序”、项目名称为“CH0803.csproj”。 2 在Main()主程序块中编写的程序代码如下:13 //1.定义委托方法,含有一个变量(数值)14 public delegate bool Speculation(Int32 numerical);15 static void Main(string[] args)16 {17 //创建一个数组18 Int32[] figures = 19 {11, 12, 13, 14, 15, 16, 17, 18, 19, 20};20 Speculation evenPredicate;//声明委托变量21 //2.委托变量要调用方法22 evenPredicate = new Speculation(IsEven);23 24 List evenNumbers = ArrayPercolate(figures,25 evenPredicate);26 showMessage(“筛选后的偶数:”, evenNumbers);27 28 List oddNumbers = ArrayPercolate(figures,29 IsOdd);30 showMessage(“筛选后的奇数:”, oddNumbers);31 32 List numberDivide3 = ArrayPercolate(figures,33 IsDivide3);34 showMessage(“能被3整除的数值:”, numberDivide3);35 Console.Read();36 }37 //找出偶数38 private static bool IsEven(Int32 numerical)39 {40 return (numerical % 2 == 0);//余数为041 }42 //找出奇数43 private static bool IsOdd(int numerical)44 {45 return (numerical % 2 == 1);46 }47 //被3整除的数值48 private static bool IsDivide3(int numerical)49 {50 return (numerical % 3 == 0);51 } 52 //读取List元素53 private static void showMessage(string str,54 Listlist){55 Console.WriteLine(str);56 //读取数组元素57 foreach(int item in list)58 Console.Write(“{0,3}”, item);59 Console.WriteLine();60 }61 //3.委托方法筛选数组元素 —— 根据传入的数组元素重新创建数组62 private static List ArrayPercolate(int[] intArray,63 Speculation special)64 {65 List result = new List();66 //读取数组元素67 foreach(int item in intArray)68 {69 if(special(item))//确认是委托方法70 result.Add(item);71 }72 return result;73 }运行:按“Ctrl F5”键来运行此程序,打开“命令提示符”窗口,运行结果如图8-6所示。程序说明? 第14行:声明委托名称Speculation,含有一个整数类型的变量。? 第20~23行:声明委托对象所要调用的方法,表示IsEven()、IsOdd()、IsDivide3()三个方法都要传入Int32类型的整数,并返回布尔值。? 第24~26行:将数组的数值调用委托方法ArrayPercolate()传入委托对象evenPredicate进行筛选,所得结果再以泛型List类来创建含有偶数值的新数组。? 第28~30行:将数组的数值调用委托方法ArrayPercolate(),将IsOdd()方法当作变量来传递并筛选出奇数,所得结果再以泛型List类来创建含有奇数值的新数组。? 第32~34行:将数组的数值调用委托方法ArrayPercolate(),将IsDivide3方法当作变量来筛选出能被3整除的数值,所得结果再以泛型List来创建数组。? 第38~41行:IsEven()方法,将接收的数值除以2,若余数为零,则表示是偶数。? 第53~60行:showMessage()方法,按List所创建的数组大小以for循环来读取并输出数组元素。? 第62~73行:委托所定义的方法ArrayPercolate(),传入figures数组,根据委托对象所传递的方法来决定它是否是List数组所要的元素,经由if语句进行判断,如果是,就以Add()方法把它加到List数组中。8.4 重点整理? “集合”可视为对象容器,用于群组和管理相关的对象。.NET Framework通过“System.Collections”命名空间提供了集合类和接口。? “索引键(key)/值(value)”是配对的集合,值存入时可以指定对象类型的索引键,便于使用时能以索引键提取对应的值。? ArrayList实现System.Collection的IList接口,会根据数组列表的大小动态增加容量,提供新增、插入、删除元素的方法,比数组更具弹性。? 在IDictionary接口中,属性Keys获取集合中所有表项的索引键,Values获取集合中所有表项的值。Add()方法将表项加入集合中,需使用key/value进行配对。? 使用Queue(队列)时,Enqueue()方法将对象加入到队列末端,Dequeue()方法会返回队列前端的对象并将其从队列中删除。? 使用Stack(堆栈)时,Peek()方法返回堆栈上端的表项,Push()方法用于把表项加到堆栈的上方,Pop()方法则是把堆栈上方的表项弹出并删除。? 委托就是把“方法”视为变量来传递。委托是一种类型,代表具有特定参数列表和返回类型的方法引用。也就是在程序中调用方法时,可以将其实例通过委托实例执行(Invoke,或调用)方法。它派生自 .NET Framework中的Delegate类。委托类型是密封的,不能作为其他类型的派生来源,且不能从Delegate派生自定义类。8.5 课后习题一、选择题(1)哪一个类可以实现IList接口?( )A. Array类 B. ArrayList类 C. Stack类 D. Queue类(2)哪一个类的表项采用先进先出(FIFO)的方式?( )A. Array类 B. ArrayList类 C. Stack类 D. Queue类(3)哪一个类的表项采用后进先出(LIFO)的方式?( )A. Array类 B. ArrayList类 C. Stack类 D. Queue类(4)在数组上使用ArrayList类,如果要重新设置数组的大小,要用哪一个属性?( )A. Capacity B. Count C. Item D. IsReadOnly(5)对于委托的描述,哪一个有误?( )A. 派生自.NET Framework中的Delegate类 B. 能作为其他类型的派生来源C. 把“方法”视为变量来传递D. 具有特定参数列表和返回类型的方法引用二、填空题(1)在IDictionary接口中,属性________获取集合中所有表项的索引键,属性____________获取集合中所有表项的值,方法________将表项加入集合中。(2)使用Queue(队列)时,____________方法会返回队列前端的对象并将其从队列中删除,____________方法将对象加入到队列末端。(3)使用Stack(堆栈)时,________方法返回堆栈上端的表项,________方法把表项加到堆栈的上方,________方法则是把堆栈上方的表项弹出并删除。三、实践题(1)IDictionary界面的实现分为3类,请简答之。(2)使用委托的概念,设计一个能计算三角形和矩形面积的委托对象,运行结果可参照图8-7。习题答案一、选择题(1)B (2)D (3)C (4)A (5)B 二、填空题(1)Keys Values Add() (2)Dequeue() Enqueue() (3)Peek() Push() Pop()三、实践题(1)● 只读:IDictionary对象无法修改。● 固定大小:IDictionary对象不允许加入或删除表项,但允许修改现有表项。● 可变大小:IDictionary对象允许加入、删除和修改表项。(2)略
评论
还没有评论。