|
关于我们
新书资讯 新书推荐 |
C#和.NET高级编程(第11版) 欢迎阅读C#编程和.NET领域最全面的指南!《C#和.NET高级编程(第11版)》没有停留在照步骤实现功能的层面,而是深入讲解那些让普通开发者进阶的核心知识点。本书第11版新增了关于EntityFramework、RazorPages、WebAPI等重磅内容,全面覆盖了C#10和.NET6的更新特性,旨在助力开发人员在C#技术方面拓展批判性思维。本书涵盖了ASP.NETCore、EntityFrameworkCore等内容,详解了新统一的.NET平台的最新更新,包括性能改进、基于.NET6的Windows桌面应用开发、XAML工具的更新,以及数据文件和数据处理。书中所有代码示例均采用C#10更新特性重写,兼顾了实用性与前沿性。翻阅本书,你将明白它成为全球C#开发人员首选参考书的原因:它能帮助你夯实面向对象开发基础,掌握特性与反射、泛型与集合,以及许多其他书籍中鲜少涉及的高级主题(如CIL操作码、动态程序集发射)。本书将助你树立实际编写C#代码的信心,自由探索.NET生态的无限潜力。?探索C#10的新特性,包括对记录的更新、新增的记录结构、全局和隐式using指令、文件级名称空间、扩展属性模式等?运用C#及现代框架,开发服务端、Web端及智能客户端应用?快速掌握使用MVC和RazorPages开发ASP.NETCoreWeb应用的技术,包括视图组件、自定义标签助手、验证机制、GDPR支持和区域开发?构建支持版本控制、增强型Swagger和基本身份验证的ASP.NETRESTful服务?深入学习EntityFrameworkCore,构建真实世界中以数据为中心的应用。本版新增了一些深入介绍的内容,包括对SQLServer时态表的支持?基于.NET6,使用WindowsPresentationFoundation开发Windows桌面应用?理解.NET底层设计理念?探索.NET6的新特性,包括单文件应用、轻量级容器镜像等 对于经验丰富的C#开发人员,本书能帮助你了解C#和.NET的最新特性。从C#7开始,本书的小节标题指出了引入或更新某个特性的版本。快速浏览目录,你便能够一眼看到新特性,然后就可以直接跳到对应的页面进行阅读并试用新特性。本书也可用作参考手册,书中提供的现成代码示例可以帮助你完成自己不熟悉的任务。对于初学者,本书采用了结构化的方式来讲解C#和面向对象编程。当你熟悉了这些主题后,就可以跳到后面的章节,开始构建ASP.NETCore或WindowsPresentationFoundation应用程序。如果还没准备好深入学习数据访问,也没有关系。本书在GitHub存储库中提供了每章的代码,所以你可以自由跳到本书的任何章节,使用GitHub存储库中提供的代码来按照自己选择的顺序学习。 作 者 简 介 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 第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 第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页面的区别。 AndrewTroelsen拥有20余年软件行业经验,历任开发者、教育工作者、作者及公共演讲者,现任团队负责人与首席工程师。他深耕微软技术栈,著有多本相关书籍,持有圣托马斯大学软件工程硕士学位(MSSE)及华盛顿大学计算语言学硕士学位(CLMS)。PhilJapikse是一位国际演讲者、微软MVP、ASPInsider和专业Scrum培训师,也是开发者社区的热情成员。他担任辛辛那提.NET用户组及软件架构师圆桌会议的首席总监,并创办了CincyDeliver大会。目前,他担任Pintas&Mullins公司的CTO兼首席架构师。 目 录 第I部分 C#和.NET 6简介 第1章 C#和.NET 6基础 3 1.1 .NET平台的一些重要优势 3 1.2 理解.NET支持周期 4 1.3 .NET平台的组成模块概述 4 1.3.1 基类库的作用 5 1.3.2 C#带来了什么 5 1.3.3 托管与非托管代码 6 1.4 使用.NET支持的其他编程语言 7 1.5 .NET程序集概述 7 1.5.1 CIL的作用 7 1.5.2 CIL的优势 10 1.5.3 将CIL编译为特定于平台的指令 10 1.5.4 .NET类型元数据的作用 10 1.5.5 程序集清单的作用 11 1.6 理解公共类型系统 12 1.6.1 CTS类类型 12 1.6.2 CTS接口类型 13 1.6.3 CTS结构类型 13 1.6.4 CTS枚举类型 13 1.6.5 CTS委托类型 14 1.6.6 CTS类型成员 14 1.6.7 CTS固有数据类型 14 1.7 理解公共语言规范 15 1.8 理解.NET运行时 17 1.9 区分程序集、名称空间和类型 17 1.9.1 在代码中访问名称空间 19 1.9.2 全局using语句(10.0新增) 19 1.9.3 文件作用域的名称空间(10.0新增) 21 1.9.4 引用外部程序集 21 1.10 使用ildasm.exe探索程序集 21 1.11 小结 22 第2章 构建C#应用程序 23 2.1 安装.NET 6 23 2.1.1 理解.NET版本号 23 2.1.2 确认.NET 6安装成功 23 2.2 使用Visual Studio构建.NET Core应用程序 25 2.2.1 安装Visual Studio 2022 (Windows) 25 2.2.2 试用Visual Studio 2022 26 2.3 使用Visual Studio Code构建.NET Core应用程序 35 2.4 找到.NET Core和C#的文档 38 2.5 小结 38 第II部分 核心C#编程 第3章 C#的核心编程结构(I) 41 3.1 分解一个简单的C#程序(C# 10更新) 41 3.1.1 使用Main()方法的不同形式(7.1更新) 43 3.1.2 使用顶级语句(9.0新增) 44 3.1.3 指定应用程序错误代码(9.0更新) 45 3.1.4 处理命令行实参(9.0更新) 47 3.1.5 在Visual Studio 2022中指定命令行实参 48 3.2 System.Environment类中的其他成员(10.0更新) 49 3.3 使用System.Console类 50 3.3.1 使用Console类执行基本的输入和输出(I/O)操作 51 3.3.2 设置控制台输出的格式 52 3.3.3 设置数值数据的格式 53 3.3.4 在控制台应用程序之外设置数值数据的格式 54 3.4 使用系统数据类型和对应的C#关键字 54 3.4.1 理解变量声明和初始化 55 3.4.2 使用固有数据类型和new操作符(9.0更新) 56 3.4.3 理解数据类型的类层次 57 3.4.4 理解数值数据类型的成员 59 3.4.5 理解System.Boolean的成员 59 3.4.6 理解System.Char的成员 59 3.4.7 解析字符串数据的值 60 3.4.8 使用TryParse从字符串数据解析值 60 3.4.9 使用System.DateTime和System.Timespan(10.0更新) 61 3.4.10 使用System.Numerics名称空间 62 3.4.11 使用数字分隔符(7.0新增) 63 3.4.12 使用二进制字面值(7.0/7.2新增) 63 3.5 使用字符串数据 64 3.5.1 执行基本字符串操作 64 3.5.2 执行字符串连接 65 3.5.3 使用转义字符 65 3.5.4 执行字符串插值 66 3.5.5 定义原样字符串(8.0更新) 69 3.5.6 字符串的相等性 69 3.5.7 String是不可变的 71 3.5.8 使用System.Text.StringBuilder类型 73 3.6 缩窄和加宽数据类型转换 73 3.6.1 使用checked关键字 75 3.6.2 设置项目级别的溢出检查(项目文件) 77 3.6.3 设置项目级别的溢出检查(Visual Studio) 77 3.6.4 使用unchecked关键字 78 3.7 理解隐式类型的局部变量 78 3.7.1 隐式声明数字 80 3.7.2 理解隐式类型的变量的限制 80 3.7.3 隐式类型的数据是强类型的数据 81 3.7.4 理解隐式类型的局部变量的有用性 82 3.8 使用C#的迭代结构 82 3.8.1 使用for循环 83 3.8.2 使用foreach循环 83 3.8.3 在foreach结构中使用隐式类型 84 3.8.4 使用while和do/while循环结构 84 3.9 作用域简介 85 3.10 使用决策结构和关系/相等性操作符 85 3.10.1 使用if/else语句 86 3.10.2 使用相等性和关系操作符 86 3.10.3 在if/else中使用模式匹配(7.0新增) 87 3.10.4 模式匹配的改进(9.0新增) 87 3.10.5 使用条件操作符(7.2、9.0更新) 88 3.10.6 使用逻辑操作符 89 3.10.7 使用switch语句 90 3.10.8 执行switch语句的模式匹配(7.0新增,9.0更新) 92 3.10.9 使用switch表达式(8.0新增) 94 3.11 小结 96 第4章 C#的核心编程结构(II) 97 4.1 理解C#的数组 97 4.1.1 C#的数组初始化语法 98 4.1.2 理解隐式类型的局部数组 99 4.1.3 定义一个Object数组 99 4.1.4 使用多维数组 100 4.1.5 将数组用作实参或返回值 101 4.1.6 使用System.Array基类 102 4.1.7 使用索引和范围(8.0新增,10.0更新) 103 4.2 理解方法 105 4.2.1 理解表达式体成员 105 4.2.2 理解局部函数(7.0新增,9.0更新) 106 4.2.3 理解静态局部函数(8.0新增) 107 4.3 理解方法参数 107 4.3.1 理解方法参数的修饰符 108 4.3.2 理解默认的参数传递行为 108 4.3.3 使用out修饰符(7.0更新) 109 4.3.4 使用ref修饰符 111 4.3.5 使用in修饰符(7.2新增) 111 4.3.6 使用params修饰符 112 4.3.7 定义可选参数 113 4.3.8 使用命名实参(7.2更新) 114 4.3.9 理解方法重载 115 4.3.10 检查参数是否为null(10.0更新) 118 4.4 理解枚举类型 118 4.4.1 控制枚举的底层存储 119 4.4.2 声明枚举变量 120 4.4.3 使用System.Enum类型 121 4.4.4 动态发现枚举的名称-值对 121 4.4.5 使用枚举、标志和位操作 122 4.5 理解结构 124 4.5.1 创建结构变量 125 4.5.2 结构的构造函数(10.0更新) 126 4.5.3 使用字段初始值(10.0新增) 127 4.5.4 使用只读结构(7.2新增) 127 4.5.5 使用只读成员(8.0新增) 128 4.5.6 使用ref结构(7.2新增) 129 4.5.7 使用可释放的ref结构(8.0新增) 129 4.6 理解值类型和引用类型 130 4.6.1 使用值类型、引用类型和赋值操作符 130 4.6.2 使用包含引用类型的值类型 132 4.6.3 按值传递引用类型 133 4.6.4 按引用传递引用类型 135 4.6.5 关于值类型和引用类型的一些细节 135 4.7 理解C#的可空类型 136 4.7.1 使用可空值类型 137 4.7.2 使用可空引用类型(8.0新增,10.0更新) 138 4.7.3 处理可空类型 141 4.8 理解元组(7.0新增/更新) 143 4.8.1 开始使用元组 143 4.8.2 使用推断的变量名称(7.1更新) 144 4.8.3 理解元组的相等性/不相等性(7.3新增) 144 4.8.4 理解作为方法返回值的元组 145 4.8.5 理解元组中使用的丢弃操作符 145 4.8.6 理解switch表达式的元组模式匹配(8.0新增) 145 4.8.7 解构元组(10.0更新) 146 4.9 小结 148 第III部分 使用C#进行面向对象编程 第5章 理解封装 151 5.1 C#的类类型简介 151 5.2 理解构造函数 153 5.2.1 理解默认构造函数的作用 154 5.2.2 定义自定义构造函数 154 5.2.3 继续介绍默认构造函数 156 5.3 理解this关键字的作用 157 5.3.1 使用this链接构造函数调用 158 5.3.2 观察构造函数的执行流 160 5.3.3 可选实参示例 162 5.4 理解static关键字 162 5.4.1 定义静态字段数据 163 5.4.2 定义静态方法 165 5.4.3 定义静态构造函数 166 5.4.4 定义静态类 168 5.4.5 通过C#的using关键字导入静态成员 168 5.5 定义面向对象编程的支柱 169 5.5.1 理解封装的作用 169 5.5.2 理解继承的作用 170 5.5.3 理解多态性的作用 171 5.6 理解C#的访问修饰符(7.2更新) 172 5.6.1 使用默认访问修饰符 173 5.6.2 使用访问修饰符和嵌套类型 173 5.7 理解第一个支柱:C#的封装服务 174 5.7.1 使用传统的访问器和修改器实现封装 175 5.7.2 使用属性进行封装 177 5.7.3 在类定义内使用属性 179 5.7.4 只读属性 181 5.7.5 只写属性 181 5.7.6 在属性中混合使用私有的和公有的get/set方法 182 5.7.7 再次讨论static关键字:定义静态属性 182 5.7.8 使用属性模式进行模式匹配(8.0新增) 182 5.7.9 展开的属性模式(10.0新增) 184 5.8 理解自动属性 185 5.8.1 使用自动属性 186 5.8.2 自动属性和默认值 187 5.8.3 初始化自动属性 188 5.9 理解对象初始化 189 5.9.1 查看对象初始化语法 189 5.9.2 使用仅初始化设置器(9.0新增) 190 5.9.3 使用初始化语法调用自定义构造函数 191 5.9.4 使用初始化语法初始化数据 192 5.10 使用常量字段数据和只读字段数据 193 5.10.1 理解常量字段数据 193 5.10.2 理解只读字段 194 5.10.3 理解静态只读字段 195 5.11 理解分部类 195 5.12 记录(9.0新增) 197 5.12.1 使用标准属性语法的不可变记录类型 198 5.12.2 使用位置语法的不可变记录类型 199 5.12.3 可变记录类型 200 5.12.4 记录类型的值相等性 200 5.12.5 使用with表达式复制记录类型 201 5.13 记录结构(10.0新增) 202 5.13.1 可变的记录结构 202 5.13.2 不可变的记录结构 203 5.13.3 解构记录结构 203 5.14 小结 203 第6章 理解继承和多态性 205 6.1 理解继承的基本机制 205 6.1.1 指定现有类的父类 206 6.1.2 多基类 207 6.1.3 使用sealed关键字 208 6.2 回顾Visual Studio的类图 208 6.3 理解OOP的第二个支柱:继承的细节 210 6.3.1 使用base关键字调用基类的构造函数 211 6.3.2 保守家族秘密:protected关键字 213 6.3.3 添加密封类 213 6.3.4 理解记录类型的继承(9.0新增) 214 6.4 包含/委托编程 217 6.5 理解OOP的第三个支柱:C#对多态性的支持 220 6.5.1 使用virtual和override关键字 220 6.5.2 在Visual Studio/ Visual Studio Code中重写虚拟方法 223 6.5.3 密封虚拟成员(10.0更新) 223 6.5.4 理解抽象类 224 6.5.5 理解多态接口 225 6.5.6 理解成员隐藏 229 6.6 理解基类/派生类的强制转换规则 230 6.6.1 使用C#的as关键字 232 6.6.2 使用C#的is关键字(7.0、9.0更新) 233 6.6.3 继续讨论模式匹配(7.0新增) 235 6.7 理解超级父类:System.Object 236 6.7.1 重写System.Object.ToString() 238 6.7.2 重写System.Object.Equals() 238 6.7.3 重写System.Object.GetHashCode() 239 6.7.4 测试修改后的Person类 240 6.7.5 使用System.Object的静态成员 241 6.8 小结 242 第7章 理解结构化异常处理 243 7.1 错误、bug和异常 243 7.2 .NET异常处理的作用 244 7.2.1 .NET异常处理的构造块 244 7.2.2 System.Exception基类 245 7.3 最简单的示例 246 7.3.1 抛出通用异常 248 7.3.2 捕获异常 249 7.3.3 将throw作为表达式(7.0新增) 250 7.4 配置异常的状态 250 7.4.1 TargetSite属性 250 7.4.2 StackTrace属性 251 7.4.3 HelpLink属性 251 7.4.4 Data属性 252 7.5 系统级异常(System.SystemException) 254 7.6 应用程序级异常(System.ApplicationException) 254 7.6.1 构建自定义异常,第一次尝试 255 7.6.2 构建自定义异常,第二次尝试 256 7.6.3 构建自定义异常,第三次尝试 257 7.7 处理多个异常 258 7.7.1 一般性的catch语句 260 7.7.2 重新抛出异常 260 7.7.3 内部异常 261 7.7.4 finally块 261 7.7.5 异常过滤器 262 7.8 使用Visual Studio调试未处理的异常 263 7.9 小结 264 第8章 使用接口 265 8.1 理解接口类型 265 8.2 定义自定义接口 268 8.3 实现接口 269 8.4 在对象级别调用接口成员 271 8.4.1 获取接口引用:as关键字 272 8.4.2 获取对象引用:is关键字(7.0更新) 272 8.5 默认实现(8.0新增) 273 8.6 静态构造函数和成员(8.0新增) 274 8.7 将接口用作参数 274 8.8 将接口用作返回值 276 8.9 接口类型的数组 276 8.10 使用Visual Studio或Visual Studio Code实现接口 278 8.11 显式接口实现 279 8.12 设计接口层次 281 8.12.1 具有默认实现的接口层次(8.0新增) 282 8.12.2 接口类型的多继承 283 8.13 IEnumerable和IEnumerator接口 285 8.13.1 使用yield关键字构建迭代器方法 287 8.13.2 构建命名迭代器 290 8.14 ICloneable接口 291 8.15 IComparable接口 295 8.15.1 使用IComparer指定多个排序顺序 298 8.15.2 自定义属性和自定义排序类型 299 8.16 小结 299 第9章 理解对象的生存期 301 9.1 类、对象和引用 301 9.2 对象生存期的基础知识 302 9.2.1 new的CIL 303 9.2.2 将对象引用设置为null 304 9.3 判断对象是否仍然存活 304 9.4 理解对象的“代” 305 9.5 垃圾回收类型 307 9.6 System.GC类型 307 9.7 构建可终结对象 311 9.7.1 重写System.Object.Finalize() 312 9.7.2 详细说明终结过程 313 9.8 构建可释放对象 314 9.8.1 重用C#的using关键字 315 9.8.2 using声明(8.0新增) 317 9.9 构建可终结、可释放的类型 317 9.10 理解对象的延迟实例化 320 9.11 小结 323 第IV部分 C#高级编程 第10章 集合和泛型 327 10.1 创建集合类的动机 327 10.1.1 System.Collections名称空间 328 10.1.2 System.Collections.Specialized名称空间简介 330 10.2 非泛型集合的问题 330 10.2.1 性能问题 331 10.2.2 类型安全性问题 334 10.2.3 初识泛型集合 337 10.3 泛型类型参数的作用 337 10.3.1 为泛型类/结构指定类型参数 338 10.3.2 为泛型成员指定类型参数 339 10.3.3 为泛型接口指定类型参数 340 10.4 System.Collections.Generic名称空间 341 10.4.1 理解集合初始化语法 342 10.4.2 使用List 10.4.3 使用Stack 10.4.4 使用Queue 10.4.5 使用PriorityQueue 10.4.6 使用SortedSet 10.4.7 使用Dictionary 10.5 System.Collections.ObjectModel名称空间 350 10.6 创建自定义泛型方法 352 10.7 创建自定义泛型结构和类 354 10.7.1 泛型的默认值表达式 355 10.7.2 default字面值表达式(7.1新增) 356 10.7.3 泛型的模式匹配(7.1新增) 357 10.8 约束类型参数 357 10.8.1 使用where关键字的示例 358 10.8.2 没有操作符约束 359 10.9 小结 360 第11章 C#的高级语言特性 361 11.1 理解索引器方法 361 10.1.1 使用字符串值索引数据 363 10.1.2 重载索引器方法 364 10.1.3 多维索引器 364 10.1.4 接口类型中的索引器定义 365 11.2 理解操作符重载 366 11.2.1 重载二元操作符 366 11.2.2 +=和-=操作符 368 11.2.3 重载一元操作符 369 11.2.4 重载相等性操作符 369 11.2.5 重载比较操作符 370 11.2.6 关于操作符重载的最后一点说明 371 11.3 理解自定义类型转换 371 11.3.1 回顾:数值转换 371 11.3.2 回顾:相关类类型之间的转换 371 11.3.3 创建自定义转换例程 372 11.3.4 Square类型的其他显式转换 375 11.3.5 定义隐式转换例程 375 11.4 理解扩展方法 376 11.4.1 定义扩展方法 377 11.4.2 调用扩展方法 378 11.4.3 导入扩展方法 378 11.4.4 扩展实现了特定接口的类型 379 11.4.5 扩展方法GetEnumerator支持foreach循环(9.0新增) 380 11.5 理解匿名类型 381 11.5.1 定义匿名类型 382 11.5.2 匿名类型的内部表示 382 11.5.3 ToString()和GetHashCode()的实现 384 11.5.4 匿名类型的相等性语义 384 11.5.5 在匿名类型中包含匿名类型 386 11.6 使用指针类型 386 11.6.1 unsafe关键字 388 11.6.2 使用*和&操作符 389 11.6.3 非安全的(和安全的)交换函数 390 11.6.4 通过指针访问字段(->操作符) 391 11.6.5 stackalloc关键字 392 11.6.6 通过fixed关键字钉住类型 392 11.6.7 sizeof关键字 393 11.7 小结 393 第12章 委托、事件和lambda表达式 395 12.1 理解委托类型 395 12.1.1 在C#中定义委托类型 396 12.1.2 System.MulticastDelegate和System.Delegate基类 398 12.2 最简单的委托示例 399 12.3 使用委托发送对象状态通知 401 12.3.1 启用多播 404 12.3.2 从委托的调用列表中移除目标 405 12.3.3 方法组转换语法 406 12.4 理解泛型委托 407 12.5 理解C#事件 410 12.5.1 C#的event关键字 411 12.5.2 事件的底层机制 413 12.5.3 监听传入的事件 413 12.5.4 使用Visual Studio简化事件注册 415 12.5.5 创建自定义事件实参 416 12.5.6 EventHandler 12.6 理解C#的匿名方法 418 12.6.1 访问局部变量 419 12.6.2 对匿名方法使用static (9.0新增) 420 12.6.3 在匿名方法中使用丢弃操作符(9.0新增) 421 12.7 理解lambda表达式 421 12.7.1 分解lambda表达式 423 12.7.2 在多条语句中处理实参 424 12.7.3 具有多个(或零个)参数的lambda表达式 425 12.7.4 在lambda表达式中使用static关键字(9.0新增) 426 12.7.5 在lambda表达式中使用丢弃操作符(9.0新增) 427 12.7.6 使用lambda表达式修改CarEvents示例 427 12.7.7 lambda和表达式体成员(7.0更新) 428 12.8 小结 428 第13章 LINQ to Objects 431 13.1 特定于LINQ的编程结构 431 13.1.1 隐式确定局部变量的类型 432 13.1.2 对象和集合初始化语法 432 13.1.3 lambda表达式 433 13.1.4 扩展方法 433 13.1.5 匿名类型 434 13.2 理解LINQ的作用 434 13.2.1 LINQ表达式是强类型的 435 13.2.2 核心的LINQ程序集 435 13.3 对原始数组应用LINQ查询 435 13.3.1 使用扩展方法的版本 437 13.3.2 不使用LINQ的版本 437 13.3.3 LINQ结果集的反射 438 13.3.4 LINQ和隐式确定类型的局部变量 439 13.3.5 LINQ和扩展方法 441 13.3.6 延迟执行的作用 441 13.3.7 立即执行的作用 443 13.4 返回LINQ查询的结果 445 13.5 对集合对象应用LINQ查询 446 13.5.1 访问被包含的子对象 447 13.5.2 对非泛型集合应用LINQ查询 448 13.5.3 使用OfType 13.6 探索C#的LINQ查询操作符 449 13.6.1 基本选择语法 450 13.6.2 获取数据子集 451 13.6.3 分页数据 451 13.6.4 使用范围分页数据(10.0新增) 453 13.6.5 使用块分页数据(10.0新增) 453 13.6.6 投影新的数据类型 454 13.6.7 投影到不同的数据类型 455 13.6.8 使用Enumerable获取计数 456 13.6.9 获取未枚举的计数(10.0新增) 456 13.6.10 翻转结果集 457 13.6.11 排序表达式 457 13.6.12 将LINQ用作更好的韦恩图工具 458 13.6.13 删除重复项 460 13.6.14 LINQ聚合操作 461 13.7 LINQ查询表达式的内部表示 462 13.7.1 使用查询操作符构建查询表达式(回顾) 463 13.7.2 使用Enumerable类型和lambda表达式构建查询表达式 463 13.7.3 使用Enumerable类型和匿名方法构建查询表达式 464 13.7.4 使用Enumerable类型和原始委托构建查询表达式 465 13.8 小结 466 第14章 进程、应用程序域和加载上下文 467 14.1 Windows进程的作用 467 14.2 使用.NET Core与进程交互 469 14.2.1 枚举运行中的进程 470 14.2.2 调查具体进程 471 14.2.3 调查进程的线程集合 471 14.2.4 调查进程的模块集合 473 14.2.5 在代码中启动和终止进程 474 14.2.6 使用ProcessStartInfo类控制进程的启动过程 475 14.2.7 通过ProcessStartInfo使用OS动词 476 14.3 理解.NET应用程序域 477 14.3.1 System.AppDomain类 478 14.3.2 与默认应用程序域交互 478 14.3.3 枚举已加载的程序集 479 14.4 使用应用程序加载上下文隔离程序集 480 14.5 总结进程、应用程序域和加载上下文 482 14.6 小结 482 第15章 多线程、并行编程和异步编程 483 15.1 进程/AppDomain/上下文/线程的关系 483 15.1.1 并发问题 484 15.1.2 线程同步的作用 484 15.2 System.Threading 名称空间 485 15.3 System.Threading.Thread类 485 15.3.1 获取当前执行线程的统计信息 486 15.3.2 Name属性 487 15.3.3 Priority属性 487 15.4 手动创建辅助线程 488 15.4.1 使用ThreadStart委托 488 15.4.2 使用 ParameterizedThreadStart 委托 490 15.4.3 AutoResetEvent 类 491 15.4.4 前台线程和后台线程 491 15.5 并发性问题 492 15.5.1 使用C#的lock关键字进行同步 494 15.5.2 使用System.Threading.Monitor类型进行同步 496 15.5.3 使用System.Threading.Interlocked类型进行同步 497 15.6 使用定时器回调进行编程 497 15.7 理解ThreadPool 499 15.8 使用任务并行库进行并行编程 500 15.8.1 System.Threading.Tasks名称空间 501 15.8.2 Parallel类的作用 501 15.8.3 使用Parallel类的数据并行性 501 15.8.4 在辅助线程上访问UI元素 505 15.8.5 Task类 505 15.8.6 处理取消请求 506 15.8.7 使用 Parallel 类实现任务并行性 507 15.9 并行LINQ查询(PLINQ) 510 15.9.1 选择使用PLINQ查询 511 15.9.2 取消PLINQ查询 511 15.10 使用async/await模式的异步调用 512 15.10.1 C#关键字async和await (7.1、9.0更新) 513 15.10.2 SynchronizationContext和async/await 514 15.10.3 ConfigureAwait的作用 514 15.10.4 异步方法的命名约定 515 15.10.5 不返回数据的异步方法 515 15.10.6 有多个await的async方法 518 15.10.7 从同步方法中调用异步方法 519 15.10.8 在catch和finally块中使用await关键字 521 15.10.9 泛化的异步返回类型(7.0新增) 521 15.10.10 局部函数使用async/await(7.0新增) 521 15.10.11 取消async/await操作 522 15.10.12 异步流(8.0新增) 525 15.10.13 Parallel.ForEachAsync()方法(10.0新增) 526 15.10.14 使用async/await更新Book Reader应用程序 527 15.10.15 async和await总结 527 15.11 小结 528 第V部分 .NET Core程序集编程 第16章 构建和配置类库 531 16.1 定义自定义名称空间(10.0更新) 531 16.1.1 使用完全限定名称解决名称冲突 533 16.1.2 使用别名解决名称冲突 533 16.1.3 创建嵌套的名称空间 534 16.1.4 使用Visual Studio 2022更改根名称空间 535 16.1.5 使用项目文件更改根名称空间 535 16.2 .NET程序集的作用 536 16.2.1 程序集促进了代码重用 536 16.2.2 程序集确定了类型边界 536 16.2.3 程序集是可版本化的单元 537 16.2.4 程序集具有自我描述性 537 16.3 理解.NET程序集的格式 537 16.3.1 安装C++性能分析工具 537 16.3.2 操作系统(Windows)文件头 538 16.3.3 CLR文件头 538 16.3.4 CIL代码、类型元数据和程序集清单 539 16.3.5 可选的程序集资源 539 16.4 类库与控制台应用程序 540 16.5 .NET Standard与.NET (Core)类库 540 16.6 使用配置文件配置应用程序 541 16.6.1 多个配置文件 542 16.6.2 使用对象(10.0更新) 543 16.6.3 其他配置选项 545 16.7 构建和使用.NET类库 546 16.7.1 探索清单 548 16.7.2 探索CIL 549 16.7.3 探索类型元数据 550 16.7.4 构建C#客户端应用程序 551 16.7.5 构建Visual Basic客户端应用程序 552 16.7.6 跨语言继承的应用 553 16.7.7 将内部类型暴露给其他程序集 553 16.8 NuGet和.NET Core 554 16.8.1 使用NuGet打包程序集 554 16.8.2 引用NuGet包 555 16.9 发布控制台应用程序(.NET 5/6更新) 556 16.9.1 发布框架依赖型应用程序 557 16.9.2 发布自包含型应用程序 557 16.10 .NET如何定位程序集 559 16.11 小结 560 第17章 类型反射、延迟绑定、特性与动态类型 561 17.1 类型元数据的必要性 561 17.1.1 查看EngineStateEnum枚举的(部分)元数据 562 17.1.2 查看Car类型的(部分)元数据 563 17.1.3 TypeRef 564 17.1.4 记录定义的程序集 564 17.1.5 记录引用的程序集 565 17.1.6 记录字符串字面值 565 17.2 理解反射 566 17.2.1 System.Type类 566 17.2.2 使用System.Object.GetType()获取类型引用 567 17.2.3 使用typeof()获取类型引用 567 17.2.4 使用System.Type.GetType()获取类型引用 568 17.3 构建自定义的元数据查看器 568 17.3.1 反射方法 568 17.3.2 反射字段和属性 569 17.3.3 反射实现的接口 570 17.3.4 显示各种杂项 570 17.3.5 添加顶级语句 571 17.3.6 反射静态类型 572 17.3.7 反射泛型类型 572 17.3.8 反射方法参数和返回值 573 17.4 动态加载程序集 574 17.5 反射框架程序集 575 17.6 理解延迟绑定 577 17.6.1 System.Activator类 577 17.6.2 调用无参数的方法 578 17.6.3 调用带参数的方法 579 17.7 理解.NET特性的作用 580 17.7.1 特性消费者 580 17.7.2 在C#中应用特性 581 17.7.3 C#特性简写表示法 581 17.7.4 为特性指定构造函数参数 582 17.7.5 Obsolete特性的实际应用 582 17.8 构建自定义特性 583 17.8.1 应用自定义特性 584 17.8.2 命名属性语法 584 17.8.3 限制特性的使用 585 17.9 程序集级别的特性 585 17.10 在项目文件中添加程序集特性 586 17.11 使用提前绑定反射特性 587 17.12 使用延迟绑定反射特性 588 17.13 反射、延迟绑定和自定义特性的实际应用 589 17.14 构建可扩展的应用程序 590 17.14.1 构建多项目的ExtendableApp解决方案 590 17.14.2 构建CommonSnappableTypes.dll 593 17.14.3 构建C#插件 593 17.14.4 构建Visual Basic插件 594 17.14.5 为ExtendableApp添加代码 594 17.15 C#中dynamic关键字的作用 596 17.15.1 调用动态声明的数据的成员 598 17.15.2 dynamic关键字的应用范围 599 17.15.3 dynamic关键字的限制 600 17.15.4 dynamic关键字的实际应用 600 17.16 动态语言运行时的作用 600 17.16.1 表达式树的作用 601 17.16.2 表达式树的动态运行时查找 601 17.17 使用动态类型简化延迟绑定调用 602 17.18 小结 604 第18章 理解CIL和动态程序集的作用 607 18.1 学习CIL语法的动机 607 18.2 探究CIL指令、属性和操作码 608 18.2.1 CIL指令的作用 608 18.2.2 CIL属性的作用 609 18.2.3 CIL操作码的作用 609 18.2.4 CIL操作码/CIL助记符的区别 609 18.3 入栈与出栈:CIL的基于栈的本质 610 18.4 理解往返工程 611 18.4.1 CIL代码标签的作用 613 18.4.2 与CIL交互:修改*.il文件 614 18.4.3 使用ILASM.EXE编译CIL代码 614 18.4.4 使用Microsoft.NET.Sdk.il项目编译CIL代码 615 18.5 理解CIL指令和属性 616 18.5.1 在CIL中指定外部引用的程序集 616 18.5.2 在CIL中定义当前程序集 617 18.5.3 在CIL中定义名称空间 617 18.5.4 在CIL中定义类类型 618 18.5.5 在CIL中定义和实现接口 619 18.5.6 在CIL中定义结构 619 18.5.7 在CIL中定义枚举 620 18.5.8 在CIL中定义泛型 620 18.5.9 编译CILTypes.il文件 621 18.6 .NET基类库、C#和CIL数据类型映射 621 18.7 在CIL中定义类型成员 622 18.7.1 在CIL中定义字段数据 622 18.7.2 在CIL中定义类型构造函数 622 18.7.3 在CIL中定义属性 623 18.7.4 定义成员参数 623 18.8 深入探讨CIL操作码 624 18.8.1 .maxstack指令 626 18.8.2 在CIL中声明局部变量 626 18.8.3 在CIL中将参数映射到局部变量 627 18.8.4 隐藏的this引用 627 18.8.5 在CIL中表示迭代结构 628 18.8.6 CIL小结 629 18.9 理解动态程序集 629 18.9.1 探索System.Reflection.Emit名称空间 629 18.9.2 System.Reflection.Emit.ILGenerator的作用 630 18.9.3 发出动态程序集 631 18.9.4 发出程序集和模块集 633 18.9.5 ModuleBuilder类型的作用 633 18.9.6 发出HelloWorld类类型和字符串成员变量 634 18.9.7 发出构造函数 634 18.9.8 发出SayHello()方法 635 18.9.9 使用动态生成的程序集 635 18.10 小结 636 第VI部分 文件处理、对象序列化和数据访问 第19章 文件I/O和对象序列化 639 19.1 探索System.IO名称空间 639 19.2 Directory(Info)和File(Info)类型 640 19.3 使用DirectoryInfo类型 641 19.3.1 使用DirectoryInfo类型枚举文件 642 19.3.2 使用DirectoryInfo类型创建子目录 643 19.4 使用Directory类型 644 19.5 使用DriveInfo类型 644 19.6 使用FileInfo类 645 19.6.1 FileInfo.Create()方法 646 19.6.2 FileInfo.Open()方法 647 19.6.3 FileInfo.OpenRead()和FileInfo.OpenWrite()方法 648 19.6.4 FileInfo.OpenText()方法 649 19.6.5 FileInfo.CreateText()和FileInfo.AppendText()方法 649 19.7 使用File类型 649 19.8 Stream抽象类 651 19.9 使用StreamWriter和StreamReader 653 19.9.1 写入文本文件 654 19.9.2 读取文本文件 654 19.9.3 直接创建StreamWriter/StreamReader类型 655 19.10 使用StringWriter和StringReader 656 19.11 使用BinaryWriter和BinaryReader 657 19.12 在代码中监视文件 658 19.13 理解对象序列化 660 19.13.1 对象图的作用 660 19.13.2 创建示例类型和顶级语句 661 19.13.3 可扩展标记语言(XML) 663 19.13.4 JavaScript Object Notation (JSON)序列化 667 19.14 小结 677 第20章 使用ADO.NET访问数据 679 20.1 ADO.NET与ADO 679 20.2 理解ADO.NET数据提供程序 679 20.3 System.Data名称空间中的类型 681 20.3.1 IDbConnection接口的作用 682 20.3.2 IDbTransaction接口的作用 682 20.3.3 IDbCommand接口的作用 683 20.3.4 IDbDataParameter和IDataParameter接口的作用 683 20.3.5 IDbDataAdapater和IDataAdapter接口的作用 684 20.3.6 IDataReader和IDataRecord接口的作用 684 20.4 使用接口抽象数据提供程序 685 20.5 设置SQL Server和Azure Data Studio 687 20.5.1 安装SQL Server 687 20.5.2 安装SQL Server IDE 689 20.5.3 连接SQL Server 689 20.6 还原AutoLot数据库备份 691 20.6.1 将备份文件复制到容器中 691 20.6.2 使用SSMS还原数据库 692 20.6.3 使用Azure Data Studio还原数据库 693 20.7 创建AutoLot数据库 694 20.7.1 创建数据库 694 20.7.2 创建表 694 20.7.3 创建表关系 696 20.7.4 创建GetPetName()存储过程 697 20.7.5 添加测试记录 698 20.8 ADO.NET数据提供程序工厂模型 699 20.8.1 一个完整的数据提供程序工厂示例 700 20.8.2 数据提供程序工厂模型的一个潜在缺陷 703 20.9 深入了解连接、命令和数据读取器 704 20.9.1 使用连接对象 705 20.9.2 使用Command对象 707 20.9.3 使用数据读取器 708 20.10 使用创建、更新和删除查询 709 20.10.1 创建Car和CarViewModel类 710 20.10.2 添加InventoryDal类 711 20.10.3 添加删除逻辑 714 20.10.4 添加更新逻辑 715 20.10.5 使用参数化的命令对象 715 20.10.6 执行存储过程 718 20.11 创建一个基于控制台的客户端应用程序 720 20.12 理解数据库事务 720 20.13 在InventoryDal中添加一个事务方法 722 20.14 使用ADO.NET执行批量复制 724 20.14.1 探索SqlBulkCopy类 724 20.14.2 创建自定义数据读取器 725 20.14.3 执行批量复制 728 20.14.4 测试批量复制 729 20.15 小结 729 第VII部分 Entity Framework Core 第21章 Entity Framework Core简介 733 21.1 对象关系映射器 734 21.2 理解Entity Framework Core的作用 734 21.3 Entity Framework的组成模块 735 21.3.1 DbContext类 735 21.3.2 DbSet 21.3.3 ChangeTracker 741 21.3.4 实体 742 21.3.5 嵌入的实体类型 768 21.3.6 查询类型 771 21.4 查询的执行 773 21.5 跟踪与非跟踪查询 774 21.6 对比代码优先与数据库优先 775 21.7 EF Core全局工具的CLI命令 775 21.7.1 migrations命令 777 21.7.2 数据库命令 780 21.7.3 DbContext命令 780 21.8 小结 782 第22章 探索Entity Framework Core 783 22.1 创建记录 783 22.1.1 实体状态 783 22.1.2 使用Add添加一条记录 784 22.1.3 使用Attach添加一条记录 785 22.1.4 一次添加多条记录 785 22.1.5 添加记录时关于identity列的考虑事项 786 22.1.6 添加对象图 788 22.1.7 添加多对多记录 789 22.1.8 添加样本记录 790 22.2 清除样本数据 791 22.3 查询数据 791 22.3.1 获取全部记录 792 22.3.2 过滤记录 792 22.3.3 排序记录 793 22.3.4 分页 795 22.3.5 获取单条记录 796 22.3.6 聚合方法 801 22.3.7 Any()和All() 802 22.3.8 从存储过程获取数据 803 22.4 查询关联数据 804 22.4.1 提前加载 804 22.4.2 显式加载 808 22.4.3 延迟加载 809 22.5 更新记录 812 22.5.1 实体状态 812 22.5.2 更新跟踪实体 812 22.5.3 更新未跟踪实体 813 22.6 删除记录 814 22.6.1 实体状态 814 22.6.2 删除跟踪记录 814 22.6.3 删除非跟踪实体 815 22.6.4 捕获失败的级联删除 815 22.7 值得关注的EF Core特性 815 22.7.1 全局查询过滤器 816 22.7.2 在LINQ中使用原生SQL查询 818 22.7.3 投影 820 22.7.4 处理数据库生成的值 821 22.7.5 并发性检查 822 22.7.6 连接的弹性 824 22.7.7 数据库函数的映射 825 22.7.8 EF.Functions 826 22.7.9 批量处理语句 828 22.7.10 值转换器 829 22.7.11 阴影属性 831 22.7.12 SQL Server对时态表的支持 833 22.8 小结 840 第23章 使用Entity Framework Core构建数据访问层 841 23.1 创建AutoLot.Dal和AutoLot.Models项目 841 23.2 添加数据库视图 842 23.3 搭建DbContext和实体 843 23.4 切换到代码优先 843 23.4.1 创建DbContext设计时工厂 844 23.4.2 创建初始迁移 844 23.4.3 应用迁移 845 23.5 创建GlobalUsings文件 845 23.6 创建自定义异常 846 23.7 完成实体和ViewModel 847 23.7.1 实体 847 23.7.2 视图模型 865 23.8 更新ApplicationDbContext 867 23.8.1 添加映射的数据库函数 868 23.8.2 处理DbContext和ChangeTracker事件 868 23.8.3 重写约定 869 23.8.4 重写SaveChanges方法 869 23.9 创建下一个迁移和更新数据库 870 23.10 使用EF迁移来创建/更新数据库对象 870 23.10.1 添加MigrationHelpers类 871 23.10.2 创建和更新迁移 872 23.10.3 应用迁移 873 23.11 添加存储库 873 23.11.1 添加IBaseViewRepo接口 873 23.11.2 添加BaseViewRepo实现 874 23.11.3 添加IBaseRepo接口 875 23.11.4 添加BaseRepo实现 876 23.11.5 添加ITemporalTableBaseRepo接口 878 23.11.6 添加TemporalTableBaseRepo实现 878 23.11.7 特定于实体的存储库接口 880 23.11.8 实现特定于实体的存储库 882 23.11.9 更新GlobalUsings.cs文件 887 23.12 在代码中处理数据库和迁移 887 23.13 数据初始化 889 23.13.1 创建样本数据 889 23.13.2 加载样本数据 891 23.14 小结 892 第24章 测试AutoLot 893 24.1 测试的准备工作 893 24.1.1 创建项目 893 24.1.2 使AutoLot.Dal的内部方法和类对AutoLot.Dal.Tests可见 894 24.1.3 添加GlobalUsings文件 894 24.1.4 初识xUnit 895 24.1.5 配置项目和DbContext实例 896 24.1.6 添加BaseTest类 897 24.1.7 添加EnsureAutoLotDatabase测试夹具类 899 24.1.8 添加集成测试类 899 24.2 查询数据库 902 24.2.1 LINQ查询 903 24.2.2 时态查询 920 24.2.3 带LINQ的SQL查询 921 24.2.4 聚合方法 922 24.2.5 Any()和All() 923 24.2.6 从存储过程获取数据 924 24.3 创建记录 924 24.3.1 添加单条记录 925 24.3.2 使用Attach添加单条记录 925 24.3.3 一次性添加多条记录 926 24.3.4 添加对象图 927 24.4 更新记录 928 24.4.1 更新跟踪实体 928 24.4.2 更新非跟踪实体 929 24.4.3 更新记录时的并发性检查 930 24.5 删除记录 930 24.5.1 删除跟踪记录 931 24.5.2 删除非跟踪实体 931 24.5.3 捕获级联删除失败 932 24.5.4 删除记录时的并发性检查 932 24.6 小结 932 第VIII部分 Windows客户端开发 第25章 Windows Presentation Foundation和XAML简介 935 25.1 WPF背后的动机 935 25.1.1 统一不同的API 936 25.1.2 通过XAML提供关注点隔离 936 25.1.3 提供优化的渲染模型 937 25.1.4 简化复杂的UI编程 937 25.2 探索WPF程序集 938 25.2.1 Application类的作用 939 25.2.2 构造Application类 939 25.2.3 枚举Windows集合 940 25.2.4 Window类的作用 940 25.3 理解WPF XAML语法 943 25.3.1 Kaxaml简介 943 25.3.2 XAML的XML名称空间和XAML“关键字” 945 25.3.3 控制类和成员变量的可见性 947 25.3.4 XAML元素、XAML属性和类型转换器 947 25.3.5 理解XAML的属性元素语法 948 25.3.6 理解XAML附加属性 949 25.3.7 理解XAML标记扩展 949 25.4 使用Visual Studio构建WPF应用程序 951 25.4.1 WPF项目模板 952 25.4.2 工具箱和XAML设计器/编辑器 952 25.4.3 使用Properties窗口设置属性 953 25.4.4 使用Properties窗口处理事件 954 25.4.5 在XAML编辑器中处理事件 955 25.4.6 Document Outline窗口 956 25.4.7 启用或禁用XAML调试器 956 25.4.8 检查App.xaml文件 957 25.4.9 将Window的XAML标记映射到C#代码 958 25.4.10 BAML的作用 960 25.4.11 解决Main()的谜题 960 25.4.12 与应用程序级数据交互 961 25.4.13 处理Window对象的关闭 962 25.4.14 拦截鼠标事件 962 25.4.15 拦截键盘事件 963 25.5 小结 964 第26章 WPF控件、布局、事件和数据绑定 965 26.1 WPF的核心控件 965 26.1.1 WPF的Ink控件 966 26.1.2 WPF的文档控件 966 26.1.3 WPF中的常用对话框 966 26.2 Visual Studio的WPF设计器概述 966 26.2.1 在Visual Studio中使用WPF控件 967 26.2.2 使用Document Outline编辑器 967 26.3 使用面板控制内容布局 968 26.3.1 在Canvas面板中定位内容 969 26.3.2 在WrapPanel面板中定位内容 970 26.3.3 在StackPanel面板中定位内容 972 26.3.4 在Grid面板中定位内容 973 26.3.5 使用GridSplitter类型的Grid 974 26.3.6 在DockPanel面板中定位内容 975 26.3.7 为面板类型启用滚动 976 26.3.8 使用Visual Studio设计器配置面板 976 26.4 使用嵌套面板构建窗口的框架 979 26.4.1 构建菜单系统 980 26.4.2 以可视化方式构建菜单 981 26.4.3 构建工具栏 981 26.4.4 构建状态栏 982 26.4.5 完成UI设计 982 26.4.6 实现MouseEnter/MouseLeave事件处理程序 983 26.4.7 实现拼写检查逻辑 983 26.5 理解WPF命令 984 26.5.1 内置的Command对象 984 26.5.2 将命令连接到Command属性 985 26.5.3 将命令连接到任意操作 986 26.5.4 使用Open和Save命令 987 26.6 理解路由事件 988 26.6.1 路由冒泡事件的作用 989 26.6.2 继续或停止冒泡 990 26.6.3 路由隧道事件的作用 990 26.7 深入介绍WPF的API和控件 992 26.8 构建Ink API选项卡 993 26.8.1 设计工具栏 993 26.8.2 RadioButton控件 994 26.8.3 添加Save、Load和Delete按钮 994 26.8.4 添加InkCanvas控件 994 26.8.5 预览窗口 995 26.8.6 处理Ink API选项卡的事件 995 26.8.7 在Toolbox中添加控件 995 26.8.8 InkCanvas控件 996 26.8.9 ComboBox控件 998 26.8.10 保存、加载和清空InkCanvas数据 999 26.9 WPF的数据绑定模型简介 1000 26.9.1 构建Data Binding选项卡 1000 26.9.2 建立数据绑定 1001 26.9.3 DataContext属性 1001 26.9.4 格式化绑定的数据 1002 26.9.5 使用IValueConverter进行数据转换 1002 26.9.6 在代码中建立数据绑定 1003 26.9.7 构建DataGrid选项卡 1004 26.10 理解依赖属性的作用 1006 26.10.1 检查现有的依赖属性 1008 26.10.2 关于CLR属性封装器的重要说明 1010 26.11 构建自定义依赖属性 1010 26.11.1 添加一个数据验证例程 1013 26.11.2 响应属性变化 1013 26.12 小结 1014 第27章 WPF图形渲染服务 1015 27.1 理解WPF的图形渲染服务 1015 27.2 使用形状渲染图形数据 1016 27.2.1 在画布上添加矩形、椭圆形和线条 1017 27.2.2 从画布中删除矩形、椭圆形和线条 1020 27.2.3 使用折线和多边形 1020 27.2.4 使用路径 1021 27.3 WPF的画刷和钢笔 1024 27.3.1 使用Visual Studio配置画刷 1024 27.3.2 在代码中配置画刷 1026 27.3.3 配置钢笔 1027 27.4 应用图形变换 1027 27.4.1 初识变换 1028 27.4.2 变换画布数据 1029 27.5 使用Visual Studio的变换编辑器 1030 27.5.1 构建初始布局 1030 27.5.2 在设计时应用变换 1032 27.5.3 在代码中变换画布 1032 27.6 使用绘图和几何图形渲染图形数据 1033 27.6.1 使用几何图形构建DrawingBrush 1034 27.6.2 使用DrawingBrush进行填充 1034 27.6.3 在DrawingImage中包含绘图类型 1035 27.7 使用矢量图形 1035 27.7.1 将示例矢量图形文件转换为XAML 1036 27.7.2 将图形数据导入WPF项目中 1036 27.7.3 与符号交互 1037 27.8 使用可视化层渲染图形数据 1037 27.8.1 Visual基类及其派生类 1038 27.8.2 DrawingVisual类的简单用法 1038 27.8.3 将可视化数据渲染到自定义布局管理器 1039 27.8.4 响应命中测试操作 1041 27.9 小结 1042 第28章 WPF资源、动画、样式和模板 1043 28.1 理解WPF的资源系统 1043 28.2 使用对象(逻辑)资源 1047 28.2.1 Resources属性的作用 1047 28.2.2 定义窗口范围的资源 1047 28.2.3 {StaticResource}标记扩展 1049 28.2.4 {DynamicResource}标记扩展 1050 28.2.5 应用程序级别的资源 1050 28.2.6 定义合并资源字典 1051 28.2.7 定义一个只包含资源的程序集 1051 28.3 理解WPF的动画服务 1052 28.3.1 Animation类类型的作用 1053 28.3.2 To、From和By属性 1053 28.3.3 Timeline基类的作用 1054 28.3.4 在C#代码中编写动画 1054 28.3.5 控制动画的节奏 1055 28.3.6 翻转和循环动画 1056 28.4 使用XAML编写动画 1057 28.4.1 故事板的作用 1057 28.4.2 事件触发器的作用 1058 28.4.3 使用离散的关键帧的动画 1058 28.5 理解WPF样式的作用 1059 28.5.1 定义和应用样式 1060 28.5.2 覆盖样式设置 1060 28.5.3 TargetType对样式的影响 1060 28.5.4 继承现有样式 1062 28.5.5 定义带触发器的样式 1062 28.5.6 定义带多个触发器的样式 1063 28.5.7 动画样式 1063 28.5.8 在代码中指定样式 1064 28.6 逻辑树、可视化树和默认模板 1065 28.6.1 通过代码检查逻辑树 1065 28.6.2 通过代码检查可视化树 1067 28.6.3 通过代码检查控件的默认模板 1067 28.7 使用触发器框架构建控件模板 1070 28.7.1 模板作为资源 1071 28.7.2 使用触发器包含视觉提示 1071 28.7.3 {TemplateBinding}标记扩展的作用 1072 28.7.4 ContentPresenter的作用 1073 28.7.5 在样式中包含模板 1073 28.8 小结 1074 第29章 WPF通知、验证、命令和MVVM 1075 29.1 模型-视图-视图模型简介 1075 29.1.1 模型 1075 29.1.2 视图 1075 29.1.3 视图模型 1076 29.1.4 贫血模型和贫血视图模型 1076 29.2 WPF的绑定通知系统 1076 29.2.1 可观察的模型和集合 1077 29.2.2 添加绑定和数据 1078 29.2.3 在代码中修改车辆数据 1079 29.2.4 可观察模型 1079 29.2.5 可观察集合 1081 29.2.6 通知和可观察对象小结 1083 29.3 WPF的验证 1083 29.3.1 为验证示例更新文件 1083 29.3.2 Validation类 1083 29.3.3 验证选项 1084 29.3.4 在WPF中利用数据注解 1092 29.3.5 自定义ErrorTemplate 1094 29.3.6 验证小结 1095 29.4 创建自定义命令 1095 29.4.1 实现ICommand接口 1096 29.4.2 添加ChangeColorCommand 1096 29.4.3 创建CommandBase类 1098 29.4.4 添加AddCarCommand类 1098 29.4.5 RelayCommand 1100 29.4.6 命令小结 1101 29.5 将代码和数据迁移到视图模型 1102 29.5.1 移动MainWindow.xaml.cs的代码 1102 29.5.2 更新MainWindow的代码和标记 1103 29.5.3 更新控件的标记 1103 29.5.4 视图模型小结 1103 29.6 为MVVM更新AutoLot.Dal 1104 29.7 小结 1104 第IX部分 ASP.NET Core 第30章 ASP.NET Core简介 1107 30.1 快速回顾ASP.NET MVC 1107 30.1.1 MVC模式简介 1107 30.1.2 ASP.NET Core和MVC模式 1108 30.2 ASP.NET Core和.NET Core 1108 30.3 创建和配置解决方案和项目 1109 30.3.1 使用Visual Studio 2022 1109 30.3.2 使用命令行 1113 30.3.3 更新Entity Framework Core的包引用 1115 30.3.4 为所有项目禁用可空引用类型 1115 30.3.5 在每个项目中创建一个GlobalUsing.cs类 1115 30.4 运行ASP.NET Core应用程序 1115 30.4.1 使用Visual Studio 1116 30.4.2 使用Visual Studio Code 1117 30.4.3 使用命令行或Terminal窗口 1117 30.4.4 在调试时修改代码 1117 30.4.5 调试ASP.NET Core应用程序 1117 30.4.6 更新AutoLot.Api和AutoLot.Web Kestrel端口 1118 30.5 ASP.NET Core中来自MVC/Web API的概念 1119 30.5.1 约定先于配置 1119 30.5.2 控制器和动作(基于MVC的Web应用程序和RESTful服务) 1120 30.5.3 目录结构约定 1122 30.5.4 路由 1123 30.5.5 模型绑定 1132 30.5.6 模型验证 1137 30.5.7 过滤器 1139 30.6 小结 1140 第31章 深入介绍ASP.NET Core 1141 31.1 ASP.NET Core中的新增特性 1141 31.2 Razor页面 1141 31.2.1 Razor页面文件 1142 31.2.2 PageModel类 1142 31.2.3 页面处理程序方法 1143 31.3 环境感知 1143 31.4 WebAppBuilder和WebApp 1145 31.4.1 Restful服务的Program.cs文件 1146 31.4.2 MVC风格的应用程序中的Program.cs文件 1147 31.4.3 基于Razor页面的应用程序中的Program.cs文件 1148 31.5 应用程序配置 1148 31.6 内置依赖注入 1149 31.6.1 在依赖注入容器中添加对Web应用程序的支持 1150 31.6.2 将DbContext派生类添加到DI容器中 1151 31.6.3 在依赖注入容器中添加自定义服务 1151 31.6.4 依赖的层次结构 1153 31.6.5 注入依赖 1153 31.6.6 在Program.cs中获取依赖 1154 31.6.7 构建共享数据服务 1155 31.7 ASP.NET Core中的选项模式 1159 31.8 HTTP客户端工厂 1161 31.8.1 基本用法 1161 31.8.2 命名客户端 1162 31.8.3 类型化客户端 1162 31.8.4 AutoLot API服务封装器 1163 31.9 部署ASP.NET Core应用程序 1171 31.10 轻量级、模块化的HTTP请求管道 1171 31.11 日志记录 1171 31.11.1 使用Serilog添加日志记录 1173 31.11.2 AutoLot日志记录框架 1178 31.11.3 将日志记录添加到数据服务中 1182 31.11.4 测试日志记录框架 1183 31.12 字符串实用方法 1184 31.13 小结 1184 第32章 使用ASP.NET Core开发RESTful服务 1185 32.1 ASP.NET Core RESTful服务简介 1185 32.2 RESTful服务中的控制器动作 1185 32.2.1 格式化后的JSON响应结果 1186 32.2.2 ApiController特性 1189 32.3 API版本化 1193 32.3.1 微软的REST API指导原则 1193 32.3.2 添加版本化NuGet包 1193 32.3.3 添加API版本支持 1194 32.3.4 API版本特性 1197 32.3.5 版本交叉 1198 32.3.6 查询字符串版本的请求和路由 1199 32.3.7 获取请求中的API版本 1201 32.3.8 URL片段版本化的路由更新 1201 32.3.9 弃用版本 1202 32.3.10 对不支持版本的请求 1202 32.3.11 添加API版本资源管理器 1203 32.4 更新Swagger/OpenAPI设置 1204 32.4.1 添加XML文档文件 1204 32.4.2 应用程序的Swagger设置 1206 32.4.3 SwaggerDefaultValues操作过滤器 1209 32.4.4 ConfigureSwaggerOptions类 1210 32.4.5 更新SwaggerGen()调用 1211 32.4.6 更新UseSwaggerUI()调用 1212 32.4.7 在Swagger UI中查看结果 1212 32.4.8 API端点的其他文档选项 1214 32.5 构建BaseCrudController 1215 32.5.1 构造函数 1216 32.5.2 Get方法 1216 32.5.3 UpdateOne方法 1218 32.5.4 AddOne方法 1219 32.5.5 DeleteOne方法 1220 32.6 CarsController 1221 32.7 剩余的控制器 1222 32.8 异常过滤器 1224 32.8.1 创建自定义异常过滤器 1224 32.8.2 测试异常过滤器 1226 32.9 添加跨源请求支持 1226 32.9.1 创建CORS策略 1226 32.9.2 将CORS策略添加到HTTP管道处理中 1227 32.10 基本身份验证 1227 32.10.1 添加和配置安全性信息 1227 32.10.2 构建基本身份验证处理程序 1228 32.10.3 注册基本身份验证处理程序并保护控制器安全 1230 32.11 小结 1232 第33章 使用MVC开发Web应用程序 1233 33.1 ASP.NET Core中的“V” 1233 33.1.1 ViewResult和动作方法 1233 33.1.2 Razor视图引擎和Razor语法 1236 33.1.3 视图 1238 33.1.4 布局 1242 33.1.5 分部视图 1243 33.1.6 将布局拆分为分部视图 1244 33.1.7 将数据发送给视图 1245 33.2 管理客户端库 1248 33.2.1 将Library Manager作为.NET全局工具安装 1248 33.2.2 在AutoLot.Mvc中添加客户端库 1248 33.3 捆绑和最小化 1251 33.3.1 捆绑 1251 33.3.2 最小化 1251 33.3.3 WebOptimizer解决方案 1251 33.4 控制器 1253 33.4.1 HomeController 1254 33.4.2 BaseCrudController 1254 33.4.3 CarsController 1261 33.5 区域 1262 33.5.1 区域路由 1263 33.5.2 MakesController区域控制器 1263 33.5.3 _ViewImports和_ViewStart 1264 33.6 标签助手 1264 33.6.1 启用标签助手 1267 33.6.2 Form标签助手 1267 33.6.3 Form Action按钮/图像标签助手 1269 33.6.4 Anchor标签助手 1269 33.6.5 Input标签助手 1269 33.6.6 TextArea标签助手 1270 33.6.7 Select标签助手 1270 33.6.8 Validation标签助手 1271 33.6.9 Environment标签助手 1272 33.6.10 Link标签助手 1273 33.6.11 Script标签助手 1274 33.6.12 Image标签助手 1275 33.7 自定义标签助手 1276 33.7.1 搭建基础 1276 33.7.2 创建基类 1276 33.7.3 Item Details标签助手 1277 33.7.4 Item Delete标签助手 1278 33.7.5 Item Edit标签助手 1279 33.7.6 Item Create标签助手 1279 33.7.7 Item List标签助手 1280 33.7.8 使自定义标签助手可见 1280 33.8 HTML助手 1281 33.8.1 DisplayFor HTML助手 1281 33.8.2 DisplayForModel HTML助手 1281 33.8.3 EditorFor和EditorForModel HTML助手 1282 33.9 Car视图 1282 33.9.1 Car List分部视图 1282 33.9.2 Index视图 1283 33.9.3 ByMake视图 1284 33.9.4 Details视图 1285 33.9.5 Create视图 1285 33.9.6 Edit视图 1286 33.9.7 Delete视图 1288 33.10 视图组件 1289 33.10.1 服务器端代码 1289 33.10.2 构建分部视图 1290 33.10.3 调用视图组件 1290 33.10.4 更新菜单 1291 33.11 自定义验证特性 1291 33.11.1 搭建基础 1292 33.11.2 服务器端验证 1294 33.11.3 客户端验证 1298 33.11.4 更新Validation Scripts分部视图 1301 33.12 通用数据保护条例支持 1301 33.12.1 添加cookie政策支持 1301 33.12.2 用于支持cookie的分部视图 1302 33.12.3 用于同意/撤回使用cookie的菜单支持 1303 33.13 完成Admin区域 1304 33.14 同时运行AutoLot.Mvc和AutoLot.Api 1306 33.14.1 使用Visual Studio 1307 33.14.2 使用命令行 1307 33.15 小结 1308 第34章 使用Razor页面开发Web应用程序 1309 34.1 Razor页面的结构 1309 34.1.1 Razor页面的PageModel类和页面处理程序方法 1309 34.1.2 Razor页面视图 1311 34.1.3 Razor视图 1313 34.1.4 分部视图 1317 34.1.5 ViewBag、ViewData和TempData 1318 34.2 向AutoLot.Web添加客户端库 1319 34.2.1 添加libman.json文件 1319 34.2.2 更新libman.json文件 1319 34.2.3 更新JavaScript和CSS引用 1321 34.3 添加并配置WebOptimizer 1322 34.4 标签助手 1323 34.4.1 启用标签助手 1324 34.4.2 Form标签助手 1324 34.4.3 Form Action按钮/图像标签助手 1325 34.4.4 Anchor标签助手 1325 34.5 自定义标签助手 1325 34.5.1 更新Program.cs 1325 34.5.2 创建基类 1326 34.5.3 Item Details标签助手 1327 34.5.4 Item Delete标签助手 1328 34.5.5 Item Edit标签助手 1328 34.5.6 Item Create标签助手 1329 34.5.7 Item List标签助手 1329 34.5.8 使自定义标签助手可见 1330 34.6 Cars Razor页面 1330 34.6.1 BasePageModel类 1330 34.6.2 Index Razor页面 1333 34.6.3 Details Razor页面 1336 34.6.4 Create Razor页面 1337 34.6.5 Edit Razor页面 1338 34.6.6 Delete Razor页面 1340 34.7 视图组件 1342 34.8 区域 1343 34.8.1 Razor页面的区域路由 1343 34.8.2 _ViewImports和_ViewStart 1343 34.8.3 Makes Razor页面 1343 34.8.4 添加区域的菜单项 1348 34.9 自定义验证特性 1349 34.10 通用数据保护条例支持 1352 34.10.1 用于支持cookie的分部视图 1352 34.10.2 用于同意/撤回使用cookie的菜单支持 1353 34.11 小结 1354
你还可能感兴趣
我要评论
|

新书资讯




