编辑推荐
● C#入门及进阶的进阶之作
● 内容全面翔实,讲解精彩
● 全新升级版,涵盖C# 6.0
作为历年来深受读者欢迎的C#指南,本书针对C# 6.0和.NET 4.6引入的新功能和新编程模式进行了全面升级,向读者展示如何编写简洁、强大、健壮、安全和易于维护的C#代码。
长期的微软极有价值专家(MVP)和技术代言人Mark Michaelis与微软C#编译器团队的前C#主要开发者Eric Lippert这两位世界C#专家对这一语言进行了全面而深入的探讨,用简洁、可下载的代码示例阐释关键构造,为读者进行C#软件开发打好基础。
无论是创建全新的代码,还是维护已有的系统,本书都让读者使用各种版本的C#进行程序开发更加容易。书中页边随附版本指示标签有助于辨识语言的创新功能在哪个版本中发挥作用。书中对初学者主题和高级主题进行了明显区分。C#的新手可通过本书快速上手,有经验的C#开发者可通过学习C# 6.0的创新技术来了解如何应对当今复杂的编程挑战。这一版还更新了使用C# 6.0构造的编码规范,编写C#代码实践一目了然。
本书适合对C#感兴趣的各层次读者,无论对初学者还是C#专家,本书都是一本很有价值的参考书。
内容简介
这是 C#领域中一部广受好评的名作,作者用一种易于理解的方式详细介绍了 C#语言的各个方面。全书共有21章和4个附录(其中有2个附录从网上下载),介绍了 C#语言的数据类型、操作符、方法、类、接口、异常处理等基本概念,深入讨论了泛型、迭代器、反射、线程和互操作性等高级主题,还介绍了LINQ技术,以及与其相关的扩展方法、分部方法、Lambda表达式、标准查询操作符和查询表达式等内容。每章开头的“思维导图”指明本章要讨论的主题,以及各个主题之间的层次关系。为了帮助读者理解各种 C#构造,书中用丰富的示例展示每一种特性,而且为每个概念都提供了相应的规范和实践,以确保代码能顺利编译、避免留下隐患,并获得相应的可维护性。
作者简介
Mark Michaelis是IntelliTect的创办者,并任该公司首席技术架构师和培训师。近二十年来,他一直是微软的MVP,2007年被评为微软技术代言人(Microsoft RegionalDirector)。他还服务于几个微软软件设计评审团队,包括C#、SharePoint和VisualStudio ALM。他经常在开发者大会上做演讲,并撰写过大量文章和书籍。
Eric Lippert是Coverity/Synopsys的C#分析团队的开发者。他曾是微软C#编译器团队的主要开发者,也是C#语言设计团队的成员之一。在微软工作的16年中,他曾参与VBScript、JScript、Windows Script Host和Visual Studio Tools for Office的设计和实现。他还服务于ECMA的JavaScript标准委员会。
译者介绍
周靖 微软极有价值专家(C# MVP),理工男,知名译者。从事计算机行业二十多年,涉猎广泛,具有深厚的技术功底和良好的文学素养,翻译风格严谨、准确、朴实、流畅,深受读者欢迎。代表译著有《Visual C#从入门到精通》《C#本质论》《Windows核心编程(第5版)》《CLR via C#(第4版)》和Walter Savitch教授的《C++程序设计》系列版本。
庞燕 北京大学理学博士。从事软件、互联网行业开发工作多年,发表多篇计算机专业相关论文,对多部计算机著作进行过审校。目前主要感兴趣的领域是大数据计算、分布式计算、软件架构和方法学,致力于提高软件开发的品质和效率。
目录
- 第1章 C#概述 1
- 1.1 Hello, World 1
- 1.2 C#语法基础 3
- 1.2.1 C#关键字 3
- 1.2.2 标识符 4
- 1.2.3 类型定义 5
- 1.2.4 Main 6
- 1.2.5 语句和语句分隔符 7
- 1.2.6 空白 8
- 1.2.7 使用变量 8
- 1.2.8 数据类型 9
- 1.2.9 变量的声明 9
- 1.2.10 变量的赋值 10
- 1.2.11 变量的使用 11
- 1.3 控制台输入和输出 11
- 1.3.1 从控制台获取输入 11
- 1.3.2 将输出写入控制台 12
- 1.3.3 注释 14
- 1.3.4 应用程序接口 16
- 1.3.5 托管执行和公共语言基础结构 16
- 1.3.6 C#和.NET版本 18
- 1.3.7 CIL和ILDASM 18
- 1.4 小结 21
- 第2章 数据类型 22
- 2.1 基本数值类型 22
- 2.1.1 整数类型 23
- 2.1.2 浮点类型 24
- 2.1.3 十进制浮点类型 24
- 2.1.4 字面量 25
- 2.2 更多基本类型 28
- 2.2.1 布尔类型 28
- 2.2.2 字符类型 28
- 2.2.3 字符串 30
- 2.3 null和void 36
- 2.3.1 null 37
- 2.3.2 void 37
- 2.4 类型的分类 39
- 2.4.1 值类型 39
- 2.4.2 引用类型 40
- 2.5 可空修饰符 41
- 2.6 数据类型之间的转换 41
- 2.6.1 显式转型 41
- 2.6.2 隐式转型 43
- 2.6.3 不使用转型操作符的类型转换 44
- 2.7 数组 45
- 2.7.1 数组的声明 46
- 2.7.2 数组的实例化和赋值 47
- 2.7.3 数组的使用 50
- 2.7.4 字符串作为数组使用 54
- 2.7.5 常见数组错误 55
- 2.8 小结 56
- 第3章 操作符和控制流 57
- 3.1 操作符 57
- 3.1.1 一元操作符正和负 58
- 3.1.2 二元算术操作符 58
- 3.1.3 复合赋值操作符 64
- 3.1.4 递增和递减操作符 65
- 3.1.5 常量表达式和常量符号 68
- 3.2 控制流程概述 68
- 3.2.1 if语句 70
- 3.2.2 嵌套if 71
- 3.3 代码块 72
- 3.4 代码块、作用域和声明空间 74
- 3.5 布尔表达式 75
- 3.5.1 关系操作符和相等性操作符 76
- 3.5.2 逻辑布尔操作符 77
- 3.5.3 逻辑求反操作符 78
- 3.5.4 条件操作符 78
- 3.5.5 空接合操作符 79
- 3.5.6 null条件操作符 80
- 3.6 按位操作符 82
- 3.6.1 移位操作符 83
- 3.6.2 按位操作符 83
- 3.6.3 按位赋值操作符 85
- 3.6.4 按位取反操作符 86
- 3.7 控制流语句(续) 86
- 3.7.1 while和do/while循环 86
- 3.7.2 for循环 88
- 3.7.3 foreach循环 90
- 3.7.4 switch语句 92
- 3.8 跳转语句 94
- 3.8.1 break语句 94
- 3.8.2 continue语句 96
- 3.8.3 goto语句 97
- 3.9 C#预处理指令 98
- 3.9.1 排除和包含代码 99
- 3.9.2 定义预处理符号 100
- 3.9.3 生成错误和警告 100
- 3.9.4 关闭警告消息 101
- 3.9.5 nowarn:选项 101
- 3.9.6 指定行号 101
- 3.9.7 可视编辑器提示 102
- 3.10 小结 103
- 第4章 方法和参数 105
- 4.1 方法的调用 106
- 4.1.1 命名空间 107
- 4.1.2 类型名称 108
- 4.1.3 作用域 109
- 4.1.4 方法名称 109
- 4.1.5 形参和实参 109
- 4.1.6 方法返回值 109
- 4.1.7 语句与方法调用的比较 110
- 4.2 方法的声明 110
- 4.2.1 形式参数声明 112
- 4.2.2 方法返回类型声明 112
- 4.2.3 表达式主体方法 113
- 4.3 using指令 114
- 4.3.1 using static指令 115
- 4.3.2 使用别名 116
- 4.4 Main()的返回值和参数 117
- 4.5 方法的参数 119
- 4.5.1 值参数 119
- 4.5.2 引用参数(ref) 120
- 4.5.3 输出参数(out) 121
- 4.5.4 参数数组 123
- 4.6 递归 125
- 4.7 方法重载 127
- 4.8 可选参数 129
- 4.9 用异常实现基本错误处理 132
- 4.9.1 捕获错误 133
- 4.9.2 使用throw语句报告错误 139
- 4.10 小结 142
- 第5章 类 143
- 5.1 类的定义和实例化 145
- 5.2 实例字段 148
- 5.2.1 实例字段的声明 148
- 5.2.2 实例字段的访问 148
- 5.3 实例方法 149
- 5.4 使用this关键字 150
- 5.5 访问修饰符 155
- 5.6 属性 157
- 5.6.1 属性的声明 158
- 5.6.2 自动实现的属性 159
- 5.6.3 属性和字段的设计编码规范 161
- 5.6.4 提供属性验证 162
- 5.6.5 只读属性和只写属性 163
- 5.6.6 属性作为虚字段使用 165
- 5.6.7 为取值方法和赋值方法指定访问修饰符 166
- 5.6.8 属性和方法调用不允许作为ref或out参数值使用 168
- 5.7 构造器 169
- 5.7.1 构造器的声明 169
- 5.7.2 默认构造器 170
- 5.7.3 对象初始化器 171
- 5.7.4 构造器的重载 172
- 5.7.5 构造器链:使用this调用另一个构造器 173
- 5.8 静态成员 177
- 5.8.1 静态字段 177
- 5.8.2 静态方法 179
- 5.8.3 静态构造器 180
- 5.8.4 静态属性 181
- 5.8.5 静态类 182
- 5.9 扩展方法 184
- 5.10 封装数据 185
- 5.10.1 const 185
- 5.10.2 readonly 186
- 5.11 嵌套类 187
- 5.12 分部类 189
- 5.12.1 定义分部类 189
- 5.12.2 分部方法 190
- 5.13 小结 192
- 第6章 继承 193
- 6.1 派生 194
- 6.1.1 基类型和派生类型之间的转型 196
- 6.1.2 private访问修饰符 197
- 6.1.3 protected访问修饰符 198
- 6.1.4 扩展方法 199
- 6.1.5 单继承 199
- 6.1.6 密封类 201
- 6.2 基类的重写 201
- 6.2.1 virtual修饰符 202
- 6.2.2 new修饰符 205
- 6.2.3 sealed修饰符 208
- 6.2.4 base成员 208
- 6.2.5 构造器 209
- 6.3 抽象类 210
- 6.4 所有类都从System.Object派生 214
- 6.5 使用is操作符验证基础类型 215
- 6.6 使用as操作符进行转换 215
- 6.7 小结 217
- 第7章 接口 218
- 7.1 接口概述 218
- 7.2 通过接口实现多态性 220
- 7.3 接口实现 223
- 7.3.1 显式成员实现 225
- 7.3.2 隐式成员实现 226
- 7.3.3 显式接口实现与隐式接口实现的比较 226
- 7.4 在实现类和接口之间转换 227
- 7.5 接口继承 227
- 7.6 多接口继承 229
- 7.7 接口上的扩展方法 230
- 7.8 通过接口实现多继承 231
- 7.9 版本控制 233
- 7.10 接口与类的比较 234
- 7.11 接口与特性的比较 235
- 7.12 小结 235
- 第8章 值类型 236
- 8.1 结构 236
- 8.1.1 结构的初始化 240
- 8.1.2 default操作符的使用 242
- 8.1.3 值类型的继承和接口 242
- 8.2 装箱 243
- 8.3 枚举 248
- 8.3.1 枚举之间的类型兼容性 251
- 8.3.2 枚举和字符串之间的转换 252
- 8.3.3 枚举作为标志使用 253
- 8.4 小结 256
- 第9章 良构类型 258
- 9.1 重写object的成员 258
- 9.1.1 重写ToString() 258
- 9.1.2 重写GetHashCode() 259
- 9.1.3 重写Equals() 261
- 9.2 操作符重载 267
- 9.2.1 比较操作符 267
- 9.2.2 二元操作符 268
- 9.2.3 赋值与二元操作符的结合 269
- 9.2.4 条件逻辑操作符 270
- 9.2.5 一元操作符 270
- 9.2.6 转换操作符 271
- 9.2.7 转换操作符的规范 272
- 9.3 引用其他程序集 273
- 9.3.1 更改程序集目标 273
- 9.3.2 引用程序集 273
- 9.4 定义命名空间 276
- 9.5 XML注释 279
- 9.5.1 将XML注释与代码构造关联到一起 279
- 9.5.2 生成XML文档文件 281
- 9.6 垃圾回收 282
- 9.7 资源清理 284
- 9.7.1 终结器 284
- 9.7.2 使用using语句进行确定性终结 285
- 9.7.3 垃圾回收、终结和IDisposable 288
- 9.8 延迟初始化 290
- 9.9 小结 291
- 第10章 异常处理 292
- 10.1 多异常类型 292
- 10.2 捕获异常 294
- 10.3 常规catch块 297
- 10.4 异常处理的规范 299
- 10.5 定义自定义异常 301
- 10.6 封装异常并重新引发 303
- 10.7 小结 306
- 第11章 泛型 307
- 11.1 如果C# 没有泛型 307
- 11.2 泛型类型概述 311
- 11.2.1 泛型类的使用 312
- 11.2.2 简单泛型类的定义 313
- 11.2.3 泛型的优点 314
- 11.2.4 类型参数命名规范 314
- 11.2.5 泛型接口和结构 315
- 11.2.6 构造器和终结器的定义 316
- 11.2.7 默认值的指定 317
- 11.2.8 多个类型参数 317
- 11.2.9 元数 318
- 11.2.10 嵌套泛型类型 319
- 11.3 约束 320
- 11.3.1 接口约束 321
- 11.3.2 类类型约束 322
- 11.3.3 struct/class约束 323
- 11.3.4 多个约束 323
- 11.3.5 构造器约束 324
- 11.3.6 约束继承 325
- 11.4 泛型方法 329
- 11.4.1 泛型方法类型推断 329
- 11.4.2 约束的指定 330
- 11.5 协变性和逆变性 332
- 11.5.1 在C# 4.0中使用out类型参数修饰符允许协变性 333
- 11.5.2 在C# 4.0中使用in类型参数修饰符允许逆变性 334
- 11.5.3 数组对不安全协变性的支持 336
- 11.6 泛型的内部机制 336
- 11.7 小结 339
- 第12章 委托和Lambda表达式 340
- 12.1 委托概述 341
- 12.1.1 背景 341
- 12.1.2 委托数据类型 342
- 12.1.3 委托类型的声明 343
- 12.1.4 委托的实例化 344
- 12.2 Lambda表达式 348
- 12.2.1 语句Lambda 348
- 12.2.2 表达式Lambda 350
- 12.3 匿名方法 351
- 12.4 通用的委托:System.Func和System.Action 353
- 12.4.1 委托没有结构相等性 354
- 12.4.2 外部变量 356
- 12.4.3 表达式树 359
- 12.5 小结 364
- 第13章 事件 366
- 13.1 使用多播委托来编码Observer模式 367
- 13.1.1 定义订阅者方法 367
- 13.1.2 定义发布者 368
- 13.1.3 连接发布者和订阅者 368
- 13.1.4 调用委托 369
- 13.1.5 检查null值 369
- 13.1.6 委托操作符 371
- 13.1.7 顺序调用 373
- 13.1.8 错误处理 375
- 13.1.9 方法返回值和传引用 377
- 13.2 事件 378
- 13.2.1 事件的作用 378
- 13.2.2 事件的声明 379
- 13.2.3 编码规范 380
- 13.2.4 泛型和委托 382
- 13.2.5 自定义事件的实现 384
- 13.3 小结 385
- 第14章 支持标准查询操作符的集合接口 386
- 14.1 匿名类型和隐式类型的局部变量声明 387
- 14.1.1 匿名类型 387
- 14.1.2 隐式类型的局部变量 388
- 14.1.3 匿名类型和隐式局部变量的更多注意事项 389
- 14.2 集合初始化器 391
- 14.3 是什么使类成为集合:IEnumerable 394
- 14.3.1 foreach和数组 394
- 14.3.2 foreach和IEnumerable 394
- 14.3.3 foreach循环内不要修改集合 398
- 14.4 标准查询操作符 398
- 14.4.1 使用Where()来筛选 401
- 14.4.2 使用Select()来投射 402
- 14.4.3 使用Count()对元素进行计数 404
- 14.4.4 推迟执行 405
- 14.4.5 使用OrderBy()和ThenBy()来排序 408
- 14.4.6 使用Join()来执行 内部联接 413
- 14.4.7 使用GroupBy分组结果 415
- 14.4.8 使用GroupJoin()实现一对多关系 416
- 14.4.9 调用SelectMany() 419
- 14.4.10 更多标准查询操作符 420
- 14.5 小结 423
- 第15章 使用查询表达式的LINQ 424
- 15.1 查询表达式概述 425
- 15.1.1 投射 426
- 15.1.2 筛选 431
- 15.1.3 排序 432
- 15.1.4 let子句 433
- 15.1.5 分组 434
- 15.1.6 使用into进行查询延续 436
- 15.1.7 用多个from子句“平整”序列的序列 437
- 15.2 查询表达式作为方法调用 438
- 15.3 小结 439
- 第16章 构建自定义集合 440
- 16.1 更多集合接口 441
- 16.1.1 IList与IDictionary 441
- 16.1.2 ICollection 442
- 16.2 主要集合类 442
- 16.2.1 列表集合:List 442
- 16.2.2 全序 445
- 16.2.3 搜索List 446
- 16.2.4 字典集合:Dictionary 447
- 16.2.5 已排序集合:SortedDictionary和SortedList 452
- 16.2.6 栈集合:Stack 452
- 16.2.7 队列集合:Queue 454
- 16.2.8 链表:LinkedList 454
- 16.3 提供索引器 454
- 16.4 返回null或者空集合 457
- 16.5 迭代器 457
- 16.5.1 迭代器的定义 458
- 16.5.2 迭代器语法 458
- 16.5.3 从迭代器生成值 459
- 16.5.4 迭代器和状态 460
- 16.5.5 更多的迭代器例子 461
- 16.5.6 将yield return语句放到循环中 463
- 16.5.7 取消更多的迭代:yield break 465
- 16.5.8 在单个类中创建多个迭代器 467
- 16.5.9 yield语句的要求 467
- 16.6 小结 468
- 第17章 反射、特性和动态编程 469
- 17.1 反射 469
- 17.1.1 使用System.Type访问元数据 470
- 17.1.2 成员调用 471
- 17.1.3 泛型类型上的反射 476
- 17.2 nameof操作符 477
- 17.3 特性 478
- 17.3.1 自定义特性 481
- 17.3.2 查找特性 482
- 17.3.3 使用构造器来初始化特性 482
- 17.3.4 System.Attribute UsageAttribute 486
- 17.3.5 命名参数 487
- 17.4 使用动态对象进行编程 495
- 17.4.1 使用dynamic调用反射 496
- 17.4.2 dynamic的原则和行为 497
- 17.4.3 为什么需要动态绑定 498
- 17.4.4 静态编译与动态编程的比较 499
- 17.4.5 实现自定义动态对象 500
- 17.5 小结 502
- 第18章 多线程处理 504
- 18.1 多线程基础 506
- 18.2 使用System.Threading 509
- 18.2.1 使用System.Threading.Thread进行异步操作 509
- 18.2.2 线程管理 511
- 18.2.3 在生产代码中不要让线程进入睡眠 511
- 18.2.4 在生产代码中不要中止线程 512
- 18.2.5 线程池处理 513
- 18.3 异步任务 514
- 18.3.1 从Thread到Task 515
- 18.3.2 理解异步任务 515
- 18.3.3 任务延续 518
- 18.3.4 用AggregateException处 理Task上的未处理异常 522
- 18.4 取消任务 527
- 18.4.1 Task.Run()是Task.Factory.StartNew()的简化形式 529
- 18.4.2 长时间运行的任务 530
- 18.4.3 对任务进行资源清理 530
- 18.5 基于任务的异步模式 531
- 18.5.1 以同步方式调用高延迟操作 531
- 18.5.2 使用TPL异步调用高 延迟操作 532
- 18.5.3 通过async和await实现基于任务的异步模式 535
- 18.5.4 异步Lambda 538
- 18.5.5 任务调度器和同步上下文 543
- 18.5.6 async/await和Windows UI 545
- 18.5.7 await操作符 546
- 18.6 并行迭代 547
- 18.7 并行执行LINQ查询 554
- 18.8 小结 557
- 第19章 线程同步 559
- 19.1 为什么要同步 560
- 19.1.1 使用Monitor来同步 563
- 19.1.2 使用lock关键字 565
- 19.1.3 lock对象的选择 566
- 19.1.4 为什么要避免锁定this、typeof(type)和string 566
- 19.1.5 将字段声明为volatile 568
- 19.1.6 使用System.Threading.Interlocked类 568
- 19.1.7 多个线程时的事件通知 569
- 19.1.8 同步设计最佳实践 570
- 19.1.9 更多的同步类型 571
- 19.1.10 线程本地存储 577
- 19.2 计时器 579
- 19.3 小结 581
- 第20章 平台互操作性和不安全的代码 582
- 20.1 平台调用 583
- 20.1.1 外部函数的声明 583
- 20.1.2 参数的数据类型 584
- 20.1.3 使用ref而不是指针 585
- 20.1.4 为顺序布局使用StructLayoutAttribute 585
- 20.1.5 错误处理 586
- 20.1.6 使用SafeHandle 588
- 20.1.7 外部函数的调用 589
- 20.1.8 用包装器简化API调用 591
- 20.1.9 函数指针映射到委托 591
- 20.1.10 编码规范 592
- 20.2 指针和地址 592
- 20.2.1 不安全的代码 592
- 20.2.2 指针的声明 593
- 20.2.3 指针的赋值 594
- 20.2.4 指针的解引用 596
- 20.2.5 访问被引用物类型的成员 598
- 20.2.6 通过委托执行不安全的代码 598
- 20.3 在C#中使用WinRT库 599
- 20.3.1 具有自定义Add/Remove处理程序的WinRT事件 600
- 20.3.2 自动变换的接口 601
- 20.3.3 基于任务的异步 601
- 20.4 小结 601
- 第21章 CLI 602
- 21.1 CLI的定义 602
- 21.2 CLI实现 603
- 21.3 C#编译成机器码 604
- 21.4 运行时 605
- 21.4.1 垃圾回收 606
- 21.4.2 .NET的垃圾回收 606
- 21.4.3 类型安全 607
- 21.4.4 代码访问安全性 607
- 21.4.5 平台可移植性 607
- 21.4.6 性能 608
- 21.5 应用程序域 608
- 21.6 程序集、清单和模块 609
- 21.7 公共中间语言 610
- 21.8 公共类型系统 611
- 21.9 公共语言规范 611
- 21.10 基类库 612
- 21.11 元数据 612
- 21.12 小结 612
- 附录A 下载和安装C#编译器与CLI平台 614
- 附录B 井字棋源代码清单 617
- 附录C 使用TPL和C# 6.0之前的多线程处理模式(网上下载)
- 附录D C# 6.0的async/await模式之前的计时器(网上下载)