作 者 简 介
Andrew Troelsen拥有20多年的软件行业从业经验。在此期间,他担任过开发人员、教育工作者、作家和公开演讲者,现在是Thomson Reuters的团队主管兼首席工程师。他撰写过多本关于微软技术领域的图书,主题包括使用ATL、COM和.NET互操作实现基于C++的COM开发、Visual Basic,以及屡获殊荣的C#和.NET平台。他拥有圣托马斯大学的软件工程理学硕士(MSSE)学位,目前正在华盛顿大学攻读计算机语言学理学硕士(CLMS)学位。
Phil Japikse是一名国际演讲者、Microsoft MVP、ASPInsider、职业Scrum培训师以及开发社区的热情参与者。Phil从.NET最初的beta版本就开始使用.NET,已经有超过35年的软件开发经验,并且从2005年开始,就深度参与敏捷社区。他是Cincinnati .NET User Group和Cincinnati Software Architect Roundtable的总监,创办了CincyDeliver (cincydeliver.org)大会,并且是National Ski Patrol的志愿者。在正常工作期间,他是Pintas & Mullins的CTO/首席架构师。他喜欢学习新技术,并总是努力提升自己的技能。你可以关注他的博客(skimedic.com)或Twitter(@skimedic)。
技术审校者简介
Eric Smith是俄亥俄州沙伦维尔市Strategic Data Systems公司的一名顾问,就职于.NET项目团队。他在2017年毕业于MAX Technical Training公司的.NET训练营,并在之前于2014年获得辛西那提大学的德语研究硕士学位。他从20世纪90年代中期就开始编写软件,并且现在只要有机会,他还是喜欢直接针对硬件进行编程。当不在计算机跟前时,他把大部分时间花在了阅读、在自己的金工车间工作以及耐力骑行上。
William Pintas是Pintas & Mullins Law Firm的一位专业软件工程师和项目经理。他在2018年毕业于纽约大学,获得了计算机科学学位。过去几年,他一直深入研究微软技术栈。目前,William正在使用ASP.NET Core、C#和Azure开发一个B2B API平台,以便在律所之间无缝共享法律信息。在空闲时间,William喜欢玩风筝冲浪和创作古典钢琴曲。
致 谢
我想对Apress出版社以及参与本书撰写工作的全体成员表示感谢。就我以往为Apress出版社撰写书籍的经验而言,他们在此次写作过程中展现出的敬业精神与支持力度,令我深感钦佩。同时,我也要感谢作为读者的你,感谢你选择阅读本书,并衷心希望它能如助力我的职业生涯一般,为你的职业发展带来裨益。最后,若没有家人的支持,我绝不可能完成这本书的撰写。他们阅读我的作品、帮我校对,还理解我为此投入了大量时间,没有他们,这一切都不可能实现!我爱他们!
——Phil Japikse
前 言
选择你自己的学习路径
从最初由Andrew撰写的版本,到我接手后撰写的后续版本,本书的目标一直是(并仍将是)帮助你成为一名高效的、知识丰富的软件工程师。与C#和.NET平台一样,本书也在每个版本中不断改进。这为你提供了选择自己的学习路径的机会。无论你是刚接触软件开发,还是已经有多年经验,本书的内容都能够引导你更上一个台阶。
对于经验丰富的C#开发人员,本书能帮助你了解C#和.NET的最新特性。从C# 7开始,本书的小节标题指出了引入或更新某个特性的版本。快速浏览目录,你便能够一眼看到新特性,然后就可以直接跳到对应的页面进行阅读并试用新特性。本书也可用作参考手册,书中提供的现成代码示例可以帮助你完成自己不熟悉的任务。
对于初学者,本书采用了结构化的方式来讲解C#和面向对象编程。当你熟悉了这些主题后,就可以跳到后面的章节,开始构建ASP.NET Core或Windows Presentation Foundation应用程序。如果还没准备好深入学习数据访问,也没有关系。本书在GitHub存储库中提供了每章的代码,所以你可以自由跳到本书的任何章节,使用GitHub存储库中提供的代码来按照自己选择的顺序学习。
作为一名作者,我无法了解你个人在某个时刻的具体需求。作为一名CTO和首席架构师,我知道我们的公司和软件工程师的长期需求,这些需求不仅仅关乎他们构建的软件,更与他们晋升技术负责人和架构师等职位时所必须的能力和知识紧密相连。我的目标是把提供给我的团队和公司的信息,同样提供给你。很可能你现在还不需要了解本书介绍的所有信息,但在你继续开发软件的过程中,很可能需要用到它们。因此,你可以选择自己的学习路径,先学习能够帮助你完成手头任务的章节,并在以后有需要的时候,继续学习其他章节。
源代码
本书的源代码托管在GitHub上的以下存储库中:https://www.Github.com/apress/pro-csharp-10。你也可以通过扫描本书封底的二维码下载这些源代码。
本书内容概述
本书内容根据逻辑分为9个部分,每个部分包含一系列在内容上相关的章节。下面简单介绍各部分和各章的内容。
第I部分:C#和.NET 6简介
第I部分旨在帮助你适应.NET平台,以及了解在创建.NET应用程序时可以使用的各种开发工具。
第1章:C#和.NET 6基础
第1章是本书内容的基础。本章的主要目标是帮助你熟悉.NET的一些构建块,如公共语言运行时(Common Language Runtime,CLR)、公共类型系统(Common Type System,CTS)、公共语言规范(Common Language Specification,CLS)和基类库(Base Class Libraries,BCL)。本章将对C#编程语言、名称空间和.NET程序集的格式进行介绍。
第2章:构建C#应用程序
本章的目标是帮助你了解编译C#源代码文件的过程。在安装了.NET SDK和运行时后,你将学习完全免费(和功能完善)的Visual Studio Community Edition,以及极为流行(并且也免费)的Visual Studio Code。你将学习如何使用Visual Studio和Visual Studio Code来创建、运行和调试.NET C#应用程序。
第II部分:核心C#编程
本部分的主题非常重要,因为无论你准备开发什么类型的.NET软件(如Web应用程序、桌面GUI应用程序、代码库、服务等),都会用到它们。在本部分,你将学习.NET的基本数据类型,进行文本操作,并学习各种C#参数修饰符的作用(包括可选实参和命名实参)。
第3章:C#的核心编程结构(I)
本章正式开始讲解C#编程语言。你将学习Main()方法的作用、顶级语句,以及关于.NET平台的基本数据类型和变量声明的各种细节。将使用System.String和System.Text.StringBuilder来处理文本数据。还将探索迭代和决策结构、模式匹配、缩窄和加宽操作,以及unchecked关键字。
第4章:C#的核心编程结构(II)
本章完成了对C#的核心编程结构的介绍。首先讲解了如何创建和处理数据数组。然后,讲解了如何构造重载的类型方法,以及使用out、ref和params关键字来定义参数。你还将学习枚举类型、结构和可空数据类型,并了解值类型和引用类型的区别。最后,你将学习元组。
第III部分:使用C#进行面向对象编程
在第III部分,你将了解C#语言的核心结构,包括面向对象编程的细节。本部分还会讲解如何处理运行时异常,并将深入介绍使用强类型接口的细节。最后,你将了解对象的生存期和垃圾回收机制。
第5章:理解封装
本章将开始介绍如何使用C#编程语言进行面向对象编程(Object-Oriented Programming,OOP)。在介绍了OOP的主要支柱(封装、继承和多态性)之后,本章的剩余部分讲解了如何使用构造函数、属性、静态成员、常量和只读字段来构建健壮的类类型。你还将学习分部类型(partial type)的定义、对象初始化语法和自动属性。本章最后将介绍记录类型和记录结构。
第6章:理解继承和多态性
本章介绍继承和多态性,它们允许构建一系列相关的类类型。在这个过程中,你将学习虚拟方法、抽象方法(和抽象基类)以及多态接口的本质。之后,你将探索使用is关键字的模式匹配。最后,本章将解释.NET平台的最终基类Syste.Object的作用。
第7章:理解结构化异常处理
本章讨论如何通过使用结构化异常处理,来处理代码库中发生的运行时意外行为。你不仅会学习用于处理这类问题的C#关键字(try、catch、throw、when和finally),还会了解应用程序级别和系统级别的异常的区别。另外,本章还将展示如何设置Visual Studio,使其在发生异常时中断程序的执行,从而能够调试你没有注意到的异常。
第8章:使用接口
本章利用你对基于对象的开发的理解,介绍了基于接口的编程。在本章中,你将学习如何定义支持多种行为的类和结构,如何在运行时发现这些行为,以及如何使用显式接口有选择地隐藏特定的行为。除了创建多个自定义接口,你还将学习如何实现.NET平台提供的标准接口。你将使用这些接口来定义可以被排序、复制、枚举和比较的对象。
第9章:理解对象的生存期
本章介绍了CLR如何使用.NET垃圾回收器管理内存。你将学习应用程序根的作用、对象生成及System.GC类型。理解了基础知识后,你将学习可释放对象(使用IDisposable接口)和终结过程(使用System.Object.Finalize()方法)。还将学习Lazy<T>类,它允许定义直到被调用者请求时才分配内存的数据。你将看到,当你想要确保堆不会因为程序实际上不需要的对象变得杂乱时,这个特性很有帮助。
第IV部分:C#高级编程
本书的这个部分将通过介绍一些更加高级但很重要的概念,深化你对C#语言的理解。本部分将讨论集合和泛型,完成对.NET类型系统的介绍。还将讲解C#的一些更加高级的特性,如扩展方法、操作符重载、匿名类型和指针操纵。然后,将介绍委托和lambda表达式,以及语言集成查询(Language Integrated Query,LINQ)。本部分的最后两章将讨论进程以及多线程/异步编程。
第10章:集合和泛型
本章探讨泛型的概念。你将了解到,泛型编程让你能够在创建类型和类型成员时使用占位符,这些占位符代表的类型将由调用者指定。简言之,泛型大大增强了应用程序的性能和类型安全性。你不仅将探索System.Collections.Generic名称空间中的各种泛型类型,还将学习如何构建自己的泛型方法和类型(可以带或不带约束)。
第11章:C#的高级语言特性
本章将通过介绍一些高级编程技术,深化你对C#编程语言的理解。在本章中,你将学习如何重载操作符,以及如何为自己的类型创建(隐式或显式的)自定义转换例程。还将学习如何构建类型索引器以及如何与之交互。你将学习如何使用扩展方法、匿名类型、分部方法以及在不安全代码上下文中使用C#指针。
第12章:委托、事件和lambda表达式
本章的目的是帮助你真正认识委托类型。简单来说,.NET委托是一个对象,它指向你的应用程序中的其他方法。通过使用这个类型,你构建的系统可以允许多个对象参与双向对话。在探索了.NET委托的用法后,你将学习C#的event关键字,它可以用于简化原始委托编程。本章最后将介绍C#的lambda操作符(=>)的作用,并探索委托、匿名方法和lambda表达式之间的关联。
第13章:LINQ to Objects
本章将介绍语言集成查询(LINQ)。LINQ允许构建强类型的查询表达式,可以将这些查询表达式用于多种LINQ目标,以处理各种各样的数据。在本章中,你将学习LINQ to Objects,它允许将LINQ表达式应用到数据容器上,如数组、集合和自定义类型。当你在本书剩余部分遇到其他LINQ API时,会发现本章介绍的知识很有帮助。
第14章:进程、应用程序域和加载上下文
在对程序集有了深刻理解后,本章将深入介绍加载到内存中的.NET Core可执行文件的组成。本章的目标是演示进程、应用程序域和上下文边界之间的关系。这些主题为第15章探讨多线程应用程序奠定了基础。
第15章:多线程、并行编程和异步编程
本章将探讨如何构建多线程应用程序,并演示创建线程安全的代码的多种技术。本章首先回顾.NET委托类型,解释委托对异步方法调用的原生支持。之后,将探索System.Threading名称空间中的类型。随后介绍了Task Parallel Library(TPL)。通过使用TPL,.NET开发人员在构建应用程序时,能够以非常简单的方式,将应用程序的工作负载分发到所有可用的CPU上。在此期间,你还将学习Parallel LINQ的作用,它能用于创建可以扩展到多个机器核心的LINQ查询。本章剩余部分介绍了如何使用async/await关键字创建非阻塞调用、局部函数、泛型 async 返回类型、异步流,以及ForEachAsync()方法。
第V部分:.NET Core程序集编程
第V部分将深入介绍.NET程序集格式的细节。你不仅将学习如何部署和配置.NET代码库,还将理解.NET二进制镜像的内部组成。本部分解释了.NET特性的作用,在运行时解析类型信息的作用,以及动态语言运行时(Dynamic Language Runtime,DLR)和C# dynamic关键字的作用。本部分的最后一章介绍公共中间语言(Common Intermediate Language,CIL)的语法和动态程序集的作用。
第16章:构建和配置类库
在高层面上,程序集这个术语用于描述使用.NET编译器创建的二进制文件。但是,.NET程序集的真实含义更丰富。在本章中,你将学习如何构建和部署程序集,以及类库和控制台应用程序的区别。最后一个小节介绍了.NET中的新选项,如单文件可执行文件的发布。
第17章:类型反射、延迟绑定、特性与动态类型
本章继续探索.NET程序集,讲解使用System.Reflection名称空间发现运行时类型的过程。通过使用这个名称空间中的类型,你构建的应用程序可以动态读取程序集的元数据。你还将学习如何使用延迟绑定,在运行时动态加载和创建类型。本章的下一个主题将探索.NET特性(包括标准特性和自定义特性)的作用。为了演示这些主题的有用性,本章将展示如何构建一个可扩展的、带有snap-in的应用程序。.NET 4.0为.NET运行时环境引入了动态语言运行时(DLR)。通过使用DLR和C#的dynamic关键字,可以定义直到运行时才真正解析的数据。使用这些特性能够显著简化一些复杂的.NET编程任务。在本章的最后,你将学习动态数据的一些实际用法,包括如何以简化的方式使用.NET的反射API。
第18章:理解CIL和动态程序集的作用
本章的目标包含两个方面。首先,比前面的章节更加详细地讲解CIL的语法和语义。其次,介绍System.Reflection.Emit名称空间的作用。通过使用这些类型,可以让构建的软件在运行时在内存中生成.NET Core程序集。正式来讲,在内存中定义和执行的程序集被称为动态程序集。
第VI部分:文件处理、对象序列化和数据访问
到了本书的这个阶段,你对C#语言和.NET程序集的格式应该有了深刻的认识。第VI部分将利用你新学到的这些知识,探索基类库提供的一些常见服务,包括文件I/O、对象序列化以及使用ADO.NET的数据库访问。
第19章:文件I/O和对象序列化
System.IO名称空间允许你与机器的文件和目录结构进行交互。在本章中,你将学习如何通过编程的方式创建(和销毁)目录系统。还将学习如何把数据添加到各种流(如基于文件的流、基于字符串的流和基于内存的流)中,以及从这些流中取出数据。本章的后半部分将讨论.NET平台提供的XML和JSON对象序列化服务。简单来说,序列化允许将一个对象(或一组相关对象)的公有状态持久化到流中,供后面使用。反序列化则是把一个对象从流中取出,放到内存中,供你的应用程序使用。
第20章:使用ADO.NET访问数据
本章讨论如何使用ADO.NET访问数据库。ADO.NET是用于.NET应用程序的数据库API。具体来说,本章将介绍.NET数据提供程序的作用,以及如何使用ADO.NET与关系数据库通信,ADO.NET由连接对象、命令对象、事务对象和数据读取器对象表示。本章还将开始创建AutoLot数据库,第VII部分将增强该数据库。
第VII部分:Entity Framework Core
本部分在前面介绍的知识的基础上,讲解如何使用Entity Framework Core访问数据库。
第21章:Entity Framework Core简介
本章介绍Entity Framework (EF) Core。EF Core构建在ADO.NET的基础上,是一个对象管理映射(ORM)框架。EF Core提供了一种使用强类型的类编写数据访问代码的方式,这些强类型的类直接映射到你的业务模型。在本章中,你将了解EF Core的构建块,包括DbContext、实体、具体化的集合类DbSet<T>,以及DbChangeTracker。之后,你将学习如何构建数据模型,并了解EF Core约定、数据注解和流畅API的作用。之后的几个小节将介绍查询的执行,以及跟踪与非跟踪实体。本章最后介绍了EF Core为.NET Core命令行接口(CLI)提供的全局工具。
第22章:探索Entity Framework Core
本章继续探索EF Core。首先深入介绍了创建、读取、更新和删除(CRUD)操作。剩余部分介绍了EF Core中比较值得注意的一些特性,包括全局查询过滤器、在LINQ中使用原生SQL查询、投影、数据库生成的值、并发性检查、连接的弹性、数据库函数映射、批处理语句、值转换器和阴影属性。本章的最后一节介绍了SQL Server的时态表支持,这是EF Core 6中的最新特性。
第23章:使用Entity Framework Core构建数据访问层
本章构建AutoLot数据访问层。首先,将第20章的AutoLot数据库搭建成DbContext派生类和实体类。其次,更新项目和数据库,改为使用代码优先的方法。将实体更新到最终版本,并使用迁移来更新数据库表和添加SQL Server对象。对数据库做的最后修改是,为第21章的存储过程创建迁移,并新增一个数据库视图。之后,为代码封装构建一组丰富的存储库。最后,添加数据初始化代码。
第24章:测试AutoLot
第24章使用xUnit测试框架,为AutoLot的数据访问层构建了自动化集成测试。本章使用60多个测试来探索查询、创建、更新和删除记录的操作。
第VIII部分:Windows客户端开发
.NET平台最初支持的桌面GUI API被命名为Windows Forms。虽然现在仍然完全支持这个API,但.NET 3.0引入了一个称为Windows Presentation Foundation (WPF)的API。与Windows Forms不同,这个框架把一些关键的服务,包括数据绑定、2D和3D图形、动画和丰富的文档,集成到了一个统一的对象模型中。这是通过使用一种称为可扩展应用程序标记语言(Extensible Application Markup Language,XAML)的声明式标记语法实现的。另外,WPF控件架构为显著改变典型控件的外观提供了一种简单的方式,只需要使用一些格式良好的XAML即可。
第25章:Windows Presentation Foundation和XAML简介
本章首先介绍了创建WPF的动机(当.NET中已经有了一个桌面开发框架时)。之后,你将学习XAML的语法。最后,将了解Visual Studio对构建WPF应用程序提供的支持。
第26章:WPF控件、布局、事件和数据绑定
本章将介绍如何使用WPF内置的控件和布局管理器。例如,你将学习如何构建菜单系统、拆分窗口、工具栏和状态栏。本章还将介绍一些WPF API(及相关的控件),包括Ink API、命令、路由事件、数据绑定模型和依赖属性。
第27章:WPF图形渲染服务
WPF是一个大量使用图形的API。因此,WPF提供了3种渲染图形的方式:形状、绘图和几何图形、可视化对象。在本章中,你将评估每种选项,并学习一些重要的图形基元,如画刷、钢笔和变换。本章还将介绍如何把矢量图形集成到WPF图形中,以及如何对图形数据执行命中测试。
第28章:WPF资源、动画、样式和模板
本章将介绍3个重要且相关的主题,它们将深化你对Windows Presentation Foundation API的理解。首先学习逻辑资源的概念。你将了解到,逻辑资源(也称为对象资源)系统提供了一种在WPF应用程序中命名和引用常用对象的方式。之后,你将学习如何定义、执行和控制动画序列。但可能让你感到意外的是,WPF动画并不局限于视频游戏或多媒体应用程序。在本章最后,你将学习WPF样式的作用。与使用CSS或ASP.NET主题引擎的Web页面类似,WPF应用程序可以为一组控件定义公共的外观和行为。
第29章:WPF通知、验证、命令和MVVM
本章首先讨论WPF框架的3种核心功能:通知、验证和命令。在介绍有关通知的小节中,你将学习可观察的模型和集合,以及它们如何使应用程序的数据和UI保持同步。之后,你将深入学习一些命令,并构建自定义命令来封装代码。在介绍有关验证的小节中,你将学习如何使用WPF应用程序中的几种验证机制。本章最后介绍了模型-视图-视图模型(Model-View-ViewModel,MVVM)模式,并创建了一个应用程序来演示MVVM模式的应用。
第IX部分:ASP.NET Core
第IX部分专门介绍如何使用ASP.NET Core构建Web应用程序。本部分介绍了ASP.NET Core的基础知识,并构建了一个RESTful服务、一个使用MVC模式的Web应用程序以及一个基于Razor页面的Web应用程序。
第30章:ASP.NET Core简介
本章介绍了ASP.NET Core。在描述了模型-视图-控制器(Model-View-Controller,MVC)模式后,创建了一个解决方案和三个ASP.NET Core项目,并探索了运行和调试应用程序的多种方式。之后,本章介绍了从ASP.NET MVC/ASP.NET Web API引入ASP.NET Core的许多特性,包括约定优先于配置、控制器和动作、路由、模型绑定和验证及过滤器。
第31章:深入介绍ASP.NET Core
本章介绍了ASP.NET Core中的许多新特性,包括Razor页面、环境感知配置系统、内置依赖注入和选项模式、HTTP客户端工厂、部署模式、HTTP请求管道和日志记录。
第32章:使用ASP.NET Core开发RESTful服务
本章完成了ASP.NET Core RESTful服务应用程序。首先介绍了如何从动作方法返回JSON及JSON配置选项。还探索了ApiAttribute为API控制器添加的功能。之后介绍了API版本化,并更新了Swagger/OpenAPI配置来支持版本化的API。创建了一个基础控制器来提供标准的CRUD操作,然后添加了特定于实体的控制器。最后,添加了一个异常过滤器,并在服务中添加了基本的身份验证机制。
第33章:使用MVC开发Web应用程序
本章完成了基于MVC的Web应用程序。首先深入介绍了视图和Razor视图引擎,包括布局和分部视图。然后,介绍了如何管理客户端库,以及如何捆绑/最小化这些库。还构建了基础控制器以及派生的、特定于实体的控制器。在应用程序中添加了区域,用于管理Make记录。之后,探索了标签助手(ASP.NET Core中的另外一个新特性),并创建了自定义的标签助手。还为动态菜单添加了应用程序的视图组件。使用了两个自定义的验证特性及相关的服务器和客户端代码为一个视图模型提供验证。最后一节介绍了ASP.NET Core中的通用数据保护条例(General Data Protection Regulation,GDPR)支持。
第34章:使用Razor页面开发Web应用程序
本章首先深入介绍了Razor页面和Razor页面视图,然后完成了AutoLot.Web应用程序。Razor页面应用程序也支持MVC应用程序的许多功能,如布局、分部视图、标签助手、视图组件、GDPR支持和区域。AutoLot.Web应用程序实现了AutoLot.Mvc应用程序的所有功能,这个过程利用了二者的相似之处,同时也指出了MVC和Razor页面的区别。
