C# .NET 入门知识点梳理
[本文由 张赐荣 整理]
1. .NET Framework基础
.NET Framework是Microsoft在Windows上的开发平台。
他包括一个公共类型系统(CTS)和一个公共语言运行库(CLR)。.NET Framework应用程序使用面向对象编程(OOP)的方法编写,通常包含托管代码。托管代码的内存管理由.NET运行库处理,其中包括垃圾自动回收。
2. .NET Framework应用程序
用.NET Framework编写的应用程序首先编译为CIL (Common Intermediate Language)。在执行应用程序时,JIT把CIL编译为本机代码。应用程序编译后,把不同的部分链接到包含CIL的程序集中。
3. C#基础
C#是包含在.NET平台中的一种主要语言,它是已有语言(如C++、Java)的一种演变,可用于编写任意应用程序,包括Web应用程序和桌面应用程序,C#更是已经成为了编写Windows桌面应用程序的最佳首选语言。
4. Console Application (控制台应用程序)
控制台应用程序是简单的命令行应用程序,本书主要用它演示技术。在VS中创建新项目时,使用Console Application模板就会创建新的控制台应用程序。要在调试模式下运行项目,可使用调试 -> 开始调试菜单项或者按下F5功能键,您也可以按下Ctrl+F5键运行但不调试程序。
5. Desktop Application (桌面应用程序 )
桌面应用程序具备标准Windows应用程序的外观和操作方式,包括最大化、最小化和关闭应用程序等大家熟悉的图标。它们是用Winform设计器创建的。
6. Web Application (网页应用程序)
Web应用程序是一种可以通过Web浏览器访问的应用。Web应用程序的一个最大好处是用户可以很容易访问并使用Web应用程序所提供的服务。用户只需要有浏览器即可,不需要再安装其他软件。
7. C#基本语法
C#是一种区分大小写的语言,每行代码都以分号结束。如果代码行太长或者想要标识嵌套的块,可以缩进代码行,以方便阅读。使用//或/*…*/语法可以包含不编译的注释。代码块可以隐藏到区域中,也是为了方便阅读。
8. 变量的概念
变量是有名称和类型的数据块。.NET定义了大量简单类型,例如数字和字符串(文本)类型,以供使用。变量只有经过声明和初始化后,才能使用。可以把字面值赋予变量,以初始化它们,变量还可在单个步骤中声明和初始化。
9. 表达式
表达式利用运算符和操作数来建立,其中运算符对操作数执行操作。运算符有3种:一元、二元和三元运算符,它们分别操作1、2和3个操作数。数学运算符对数值执行操作,赋值运算符把表达式的结果放在变量中。运算符有固定的优先级,优先级确定了运算符在表达式中的处理顺序。
10. 语句
语句是C#程序的基本构建块。一条语句相当于一条完整的计算机指令。在C#中,大部分语句都以分号结尾。
11. 名称空间 (namespace)
.NET应用程序中定义的所有名称,包括变量名,都包含在名称空间中。名称空间采用层次结构,我们通常需要根据包含名称的名称空间来限定名称,以便访问它们
12. 布尔逻辑 (Bool)
布尔逻辑使用布尔值(true和false)计算条件。布尔运算符用于比较数值,返回布尔结果。一些布尔运算符也用于对数值的底层位结构执行按位操作,还有一些专门的按位运算符。
13. 分支
可使用布尔逻辑控制程序执行流程。计算为布尔值的表达式可以用于确定是否执行某个代码块,可以使用if语句或?:(三元)运算符进行简单的分支,或者使用switch语句同时检查多个条件。
14. 循环
循环允许根据指定的条件多次执行代码块。使用do和while循环可在布尔表达式为true时执行代码,使用for循环可在循环代码中包含一个计数器。循环可以使用continue中断当前的迭代,或者使用break完全中断。一些循环只能在用户强制中断时结束,这些循环称为无限循环。
15. 类型转换
值可以从一种类型转换为另一种类型,但在转换时应遵循一些规则。隐式转换是自动进行的,但只有当源值类型的所有可能值都可以在目标值类型中使用时,才能进行隐式转换。也可以进行显式转换,但可能得不到期望的值,甚至可能出错。
16. 枚举 (enum)
枚举是包含一组离散值的类型,每个离散值都有一个名称。枚举用enum关键字定义,以便在代码中理解它们,因为它们的可读性都很高。枚举有基本的数值类型(默认是int),可使用枚举值的这个属性在枚举值和数值之间转换,或者标识枚举值。
17. 结构 (struct)
结构是同时包含几个不同值的类型。结构用struct关键字定义。包含在结构中的每个值都有名称和类型,存储在结构中的每个值的类型不一定相同。
18. 数组
数组是同类型数值的集合。数组有固定的大小或长度,确定了数组可以包含多少个值。可以定义多维数组或锯齿数组来保存不同数量和形状的数据。还可以使用foreach循环来迭代数组中的值。
19. 定义函数
用函数名、0个或多个参数及返回类型来定义函数。函数的名称和参数统称为函数的签名。可以定义名称相同但签名不同的多个函数——这称为函数重载。也可以在结构类型中定义函数。
20. 返回值和参数
函数的返回类型可以是任意类型,如果函数没有返回值,其返回类型就是void。参数也可以是任意类型,由一个用逗号分隔的类型和名称对组成。个数不定的特定类型的参数可以通过参数数组来指定。参数可以指定为ref或out,以便给调用者返回值。调用函数时,所指定的参数的类型和顺序必须匹配函数的定义,并且如果参数定义中使用了ref或out关键字,那么在调用函数时也必须包括对应的ref或out关键字。
21. 变量作用域
变量根据定义它们的代码块来界定其使用范围。代码块包括方法和其他结构,例如循环体。可在不同的作用域中定义多个不同的同名变量。
22. 命令行参数
在执行应用程序时,控制台应用程序中的Main()函数可以接收传送给应用程序的命令行参数。这些参数用空格隔开,较长的参数可以放在引号中传送。
23. 委托 (delegate)
除了直接调用函数外,还可以通过委托调用它们。委托是用返回类型和参数列表定义的变量。给定的委托类型可以匹配返回类型和参数与委托定义相同的方法。
24. 错误类型
编译期间的语法错误和运行期间的致命错误都会使应用程序完全失败,语义错误(或逻辑错误)比较微妙,可能会使应用程序执行不正确,或者以未预料到的方式执行。
25. 输出调试信息
我们可以编写代码,把有帮助的信息输出到Output窗口中,以帮助在IDE中进行调试。为此需要使用Debug和Trace系列函数,其中Debug函数在发布版本中会被忽略。对于投入生产的应用程序,应将调试输出写入日志文件。另外,还可以使用跟踪点输出调试信息。
26. 中断模式
可以通过断点、判定语句,或者在发生未处理的异常时,手工进入中断模式(实际上就是暂停应用程序的状态)。可以在代码的任意位置添加断点,还可以把断点配置为仅在特定条件下中断执行。在中断模式下,可以检查变量的内容(使用各种调试信息窗口),每次执行一行代码,以帮助确定哪里出现了错误。
27. 异常
异常是运行期间发生的错误,可以通过编程方式捕获和处理这种错误,以防应用程序终止。调用函数或处理变量时,可能会发生许多不同类型的异常。还可以使用throw关键字生成异常。
28. 异常处理
代码中未处理的异常会使应用程序终止。使用try、catch和finally代码块处理异常。try块标记了一个启用异常处理的代码段,catch块包含的代码仅在异常发生时执行,它可以匹配特定类型的异常,还可以包含多个catch块。finally块指定异常处理完毕后执行的代码,如果没有发生异常,finally块就指定在try块执行完毕后执行的代码。只能包含一个finally块,如果包含了catch块,finally块就是可选的。
29. 面向对象程序设计
面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)的主要思想是把构成问题的各个事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙一个事物在整个解决问题的步骤中的行为。面向对象程序设计中的概念主要包括:对象、类、数据抽象、继承、动态绑定、数据封装、多态性、消息传递。通过这些概念面向对象的思想得到了具体的体现。
30. 对象(object)和类(class)
对象是OOP(面向对象)应用程序的组成部件。类是用于实例化对象的类型定义。对象可以包含数据,提供其他代码可以使用的操作。数据可以通过属性供外部代码使用,操作可以通过方法供外部代码使用。属性和方法都称为类的成员。属性可以进行读取访问、写入访问或读写访问。类成员可以是公共的(可用于所有代码)或私有的(只有类定义中的代码可以使用)。在.NET中,所有的东西都是对象。
31. 对象的生命周期
对象通过调用它的一个构造函数来实例化。不再需要对象时,就执行其析构函数,以删除它。要清理对象,常常需要手工删除它。
32. 静态成员和实例成员
实例成员只能在类的对象实例上使用,静态成员只能直接通过类定义使用,它不与实例关联。
33. 接口(interface)
接口是可以在类上实现的公共属性和方法的集合。可将实现了一个接口的类的对象赋值给对应实例类型的变量。之后通过该变量,可以使用该接口定义的成员
34. 继承
继承是一个类定义派生于另一个类定义的机制。类从其父类中继承成员,每个类都只能有一个父类。子类不能访问父类的私有成员,但可以定义受保护的成员,受保护的成员只能在该类和派生于该类的子类中使用。子类可以重写父类中的虚拟成员。所有的类都有一个以System.Object结尾的继承链,在C#中,System.Object有一个别名object
35. 多态性
从一个派生类实例化的所有对象都可以看成其父类的实例
36. 对象关系和特性
对象可以包含其他对象,也可以表示其他对象的集合。要在表达式中处理对象,常常需要通过运算符重载,定义运算符如何处理对象。对象可以提供事件,事件因某种内部处理而被触发,客户端代码通过提供事件处理程序来响应事件
37. 类和接口定义
类用class关键字定义,接口用interface关键字定义。可以使用public和internal关键字来定义类和接口的可访问性,类可以定义为abstract或sealed,以便控制继承性。父类和父接口在一个用逗号分隔的列表中指定,放在类或接口名和一个冒号的后面。在类定义中,只能指定一个父类,且必须是列表中的第一项。
38. 构造函数和析构函数
类自动带有默认的构造函数和析构函数的实现代码,我们很少需要提供自己的析构函数。可以使用可访问性、类名和可能需要的任何参数来定义构造函数。基类的构造函数在派生类的构造函数之前执行,使用this和base构造函数初始化器关键字,可以控制类中这些构造函数的执行顺序。
39. 类库
可以创建只包含类定义的类库项目。这些项目不能直接执行,而必须通过客户代码在可执行程序中访问。VS为创建、修改和测试类提供了各种工具。
40. 类系列
类可以组合为系列,以提供公共的操作或共享公共特性。为此,可从共享的基类(可以是抽象的)中继承,或者实现接口。
41. 结构定义
结构的定义方式与类非常类似,但结构是值类型,而类是引用类型
42. 复制对象
复制对象时,必须注意应复制该对象包含的其他对象,而不是仅复制这些对象的引用。复制引用称为浅度复制,而完全复制称为深度复制。可用ICloneable接口作为一个框架,提供类定义中的深度复制功能
43. 成员定义
可在类中定义字段、方法和属性成员。字段用可访问性、名称和类型定义,方法用可访问性、返回类型、名称和参数定义,属性用可访问性、名称、get和/或set存取器定义。各个属性存取器可以有自己的可访问性,但它必须低于整个属性的可访问性。
44. 成员隐藏和重写
属性和方法可在基类中定义为抽象或虚拟,以定义继承。派生类必须实现抽象的成员,使用override关键字可以重写虚拟的成员。派生类还可以用new关键字提供新的实现代码,用sealed关键字禁止进一步重写虚拟成员。可用base关键字调用基类的实现代码。
45. 接口的实现
实现了接口的类必须实现该接口定义为公共的所有成员。可以隐式或显式实现接口,其中显式实现代码只能通过接口引用来使用。
46. 分部类定义
使用partial关键字可以把类定义放在多个代码文件中。还可以使用partial关键字创建部分方法。部分方法有一些限制,包括没有返回值或out参数,如果没有提供实现代码,就不能编译部分方法。
47. 定义集合
集合是可以包含其他类的实例的类。要定义集合,可从CollectionBase中派生,或者自己实现集合接口,例如IEnumerable、ICollection和IList。一般需要为集合定义一个索引器,以使用collection[index]语法来访问集合成员。
48. 字典
可以定义键值对集合,即字典,字典中的每一项都有一个关联的键。在字典中,键可以用于标识一项,而不必使用该项的索引。定义字典时,可以实现IDictionary,或者从DictionaryBase派生类。
49. 迭代器
可以实现一个迭代器,来控制循环代码如何在其循环过程中获取值。要迭代一个类,需要实现GetEnumerator()方法,其返回类型是IEnumerator。要迭代类的成员,例如方法,可使用IEnumerable返回类型。在迭代器的代码块中,使用yield关键字返回值。
50. 类型比较
可使用GetType()方法获得对象的类型,使用typeof()运算符可以获得类的类型。可以比较这些类型值。还可以使用is运算符确定对象是否与某个类类型兼容。
51. 值比较
如果希望类的实例可以用标准的C#运算符进行比较,就必须在类定义中重载这些运算符。对于其他类型的值比较,可使用实现了IComparable或IComparer接口的类。这些接口特别适用于集合的排序。
52. as运算符
可使用as运算符把一个值转换为引用类型。如果不能进行转换,as运算符就返回null值
53. 使用泛型类型
泛型类型需要一个或多个类型参数才能工作。在声明变量时,传送需要的类型参数,就可以把泛型类型用作变量的类型。为此,应把逗号分隔的类型名列表放在尖括号中。
54. 可空类型
可空类型可使用指定值类型的任意值或null值。使用Nullable
55. "??" 运算符
空结合运算符返回第一个操作数的值,如果第一个操作数是null,就返回第二个操作数的值。
56. 泛型集合
泛型集合非常有用,因为它们内置了强类型化功能。可使用List
57. 定义泛型类
泛型类型的定义十分类似于其他类型,但在指定类型名时需要添加泛型类型参数。与使用泛型类型一样,也需要把这些参数指定为逗号分隔的列表,并放在尖括号中。在使用类型名的地方都可以使用泛型类型参数,例如可在方法的返回值和参数中使用它们。
58. 泛型类型的参数约束
为了高效地在泛型类型代码中使用泛型类型参数,可以在使用类型时约束可以提供的类型。可以根据基类、所支持的接口、是否必须是值类型或引用类型以及是否支持无参数的构造函数等,来约束类型参数。如果没有这些约束,就必须使用default关键字来实例化泛型类型的变量。
59. 其他泛型类型
除类之外,还可以定义泛型接口、委托和方法。
60. 变体(协变与逆变)
变体是类似于多态性的一个概念,但应用于类型参数。它允许使用一个泛型类型替代另一个泛型类型,这些泛型类型仅在所使用的泛型类型参数上有区别。协变允许在两种类型之间转换,其中目标类型有一个类型参数,它是源类型的类型参数的基类。逆变允许进行相反的转换。协变类型参数用out参数定义,只能用作返回类型和属性get访问器的类型。逆变类型参数用in参数定义,只能用作方法的参数。
61. 名称空间限定符
为了避免名称空间限定的模糊性,可以使用::运算符强制编译器使用已创建好的别名。还可以使用global名称空间作为顶级名称空间的别名。
62. 定制异常
从根类Exception中派生,就可以创建自己的异常类。这是有益的,因为可以更多地控制特定异常的捕获,并允许定制包含在异常中的数据,以高效地处理它。
63. 事件处理
许多类都提供了事件,在代码中发生某个触发器时,就会引发这些事件。可为这些事件编写处理程序,在引发事件时执行代码。这种双向通信方式是响应代码的一种良好机制,不必编写可能要轮询对象以获知变化的复杂、令人感到费解的代码。
64. 事件定义
可以定义自己的事件类型,这涉及给事件的处理程序创建指定的事件和委托类型。可以使用标准的、无返回类型的委托类型和派生于System.EventArgs的定制事件参数,使事件处理程序有多种用途。还可以使用EventHandler和EventHandler
65. 匿名方法
为使代码更便于阅读,常可以使用匿名方法来替代完整的事件处理方法。这表示,在添加事件处理程序的地方直接定义要在引发事件时执行的代码,为此需要使用delegate关键字。
66. 特性
有时,或者是由于所用框架的要求,或者是由于自己的需要,在代码中会用到特性。通过使用[AttributeName]语法,可以向类、方法和其他成员添加特性;通过从System.Attribute派生,可以创建自己的特性。通过反射可读取特性值。
67. 初始化器
可使用初始化器在创建对象或集合的同时初始化它们。这两种初始化器都包括一个放在花括号中的代码块。对象初始化器可以提供一个逗号分隔的属性名/值对列表,来设置属性值。集合初始化器仅需要逗号分隔的值列表。使用对象初始化器时,还可以使用非默认的构造函数。
68. 类型推断
声明变量时,使用var关键字允许忽略变量的类型。但只有类型可以在编译期间确定时才可以这么做。使用var没有违反C#的强类型化规则,因为用var声明的变量只能有一种类型。
69. 匿名类型
对于用于数据存储的许多简单类型,并非必须定义类型。相反,可以使用匿名类型,其成员根据用途来推断。使用对象初始化器语法来定义匿名类型,每个设置的属性都定义为只读属性。
70. 动态查找
使用dynamic关键字定义dynamic类型的变量,可以存储任意值。接着就可以使用一般的属性或方法语法来访问该变量中包含的值的成员,这些成员仅在运行期间检查。如果在运行期间,尝试访问一个不存在的成员,就会抛出一个异常。这种动态的类型化显著简化了访问非.NET类型或类型信息不能在编译期间获得的.NET类型的语法。但是,在使用动态类型时要谨慎,因为无法在编译期间检查代码。实现IDynamicMetaObjectProvider接口,可以控制动态查找的行为。
71. 可选的方法参数
我们常常可以定义带许多参数的方法,但其中的许多参数都很少使用。可以提供多个方法重载,而不是强制客户代码为很少使用的参数提供值。另外,也可以把这些参数定义为可选参数(并为未指定值的参数提供默认值)。调用方法的客户代码就可以仅指定需要的参数。
72. 命名的方法参数
客户代码可以根据位置或名称(或者根据位置和名称,其中位置参数放在前面)来指定方法的参数。命名的参数可按任意顺序指定。这尤其适用于和可选参数一起使用的场合。
73. Lambda表达式
Lambda表达式实际上是定义匿名方法的一种快捷方式,而且具有额外的功能,例如隐式的类型化。定义Lambda表达式时,需要使用逗号分隔的参数列表(如果没有参数,就使用空括号)、=>运算符和一个表达式。该表达式可以是放在花括号中的代码块。Lambda表达式至多可以有8个参数和一个可选的返回类型,Lambda表达式可以用Action、Action<>和Func<>委托类型来表示。许多可用于集合的LINQ扩展方法都使用Lambda表达式参数。
74. 流(stream)
流是序列化设备的一种抽象表示,可以一次从序列化设备中读取或写入一个字节。文件就是这种设备的一个例子。流有两种类型:输入和输出,分别用于读取和写入设备。
75. 文件访问类
.NET中具有大量抽象了文件系统访问的类,包括通过静态方法处理文件和目录的File和Directory,可实例化为表示特定文件和目录的FileInfo和DirectoryInfo。后两个类在对文件和目录执行多个操作时使用,因为这两个类不要求为每个方法调用指定路径。可以在文件和目录上执行的典型操作包括查看和修改属性,以及创建、删除和复制操作
76. 文件路径
文件和目录路径可以是绝对的或相对的。绝对路径给出了某位置的完整描述,从包含它的驱动器的根目录开始。所有父目录都与子目录用反斜杠隔开。相对路径与之类似,但从文件系统的指定点开始,例如执行应用程序的目录(工作目录)。浏览文件系统时,常使用父目录的别名..
77. FileStream对象
FileStream对象允许访问文件的内容,以进行读写。它以字节为单位访问文件数据,所以并不总是访问文件数据的最佳选项。FileStream实例维护着文件内部的一个位置字节索引,这样就可以浏览文件的内容了。以这种方式访问文件的任意位置称为随机访问
78. 读写流
一种读写文件数据的更简便方法是使用StreamReader和StreamWriter类,以及FileStream。它们允许读写字符和字符串数据,而不是处理字节。这些类型提供了我们熟悉的处理字符串的方法,包括ReadLine()和WriteLine()。因为它们处理的是字符串数据,所以使用这些类,可以更加方便地处理逗号分隔的文件(这是表示结构化数据的常见方式)
79. 压缩文件
可使用DeflateStream和GZipStream压缩流类来读写文件中的压缩数据。这些类与FileStream一样,也处理字节数据,但可以通过StreamReader和StreamWriter类访问数据,以简化代码
80. 监控文件系统
可使用FileSystemWatcher类监控文件系统数据的变化。可以监控文件和目录,如有必要,还可以提供一个过滤器,根据需要仅修改有特定扩展名的文件。FileSystemWatcher实例通过触发事件,来通知我们发生了变化,这些事件可以在代码中处理
81. XML基本语法
用XML声明、XML名称空间、XML元素和特性来创建XML文档。XML声明定义了XML版本,XML名称空间用于定义词汇表,XML元素和特性用于定义XML文档的内容。
82. JSON基本语法
JSON是传输时JavaScript和Web服务使用的一种数据语言。JSON比XML更紧凑,但难以读懂。
83. XML模式
XML模式用于定义XML文档的结构。需要与第三方交换信息时,模式特别有用。对所交换的数据的模式达成一致后,我们和第三方就可以检查该文档是否有效。
84. XML DOM
XML文档对象模型(DOM)是.NET Framework的基础,提供了创建和操纵XML的功能。
85. JSON包
可以使用JSON包(如Newtonsoft)将XML转换为JSON,将JSON转换为XML,用JSON完成其他操作,类似于用.NET类处理XML。
86. XPath
XPath是在XML文档中查询数据的方式之一。要使用XPath,就必须熟悉XML文档的结构,这样才能从中选择各个元素。尽管XPath可以用于任何格式良好的XML文档,但创建查询时必须了解文档的结构,这意味着确保文档有效,也就确保了只要文档对于同一个模式而言是有效的,查询就可以用于多个文档。
87. LINQ的概念和使用场合
LINQ是内置于C#中的一种查询语言。使用LINQ可以在大型的对象集合、XML或数据库中查询数据。
88. LINQ查询的组成部分
LINQ查询包含from、where、select和orderby子句。
89. 获取LINQ查询的结果的方式
使用foreach语句迭代LINQ查询的结果。
90. 延迟执行
LINQ查询会延迟到执行foreach语句时执行。
91. 方法语法和查询语法
简单的LINQ查询使用查询语法,较高级的查询使用方法查询。对于任意给定的查询,查询语法和方法语法的结果相同。
92. Lambda表达式
Lambda表达式可以使用方法语法,随时声明一个用于LINQ查询的方法。
93. 聚合运算符
使用LINQ聚合运算符获得大型数据集的信息,而不必迭代每个结果。
94. 组合查询
使用组合查询给数据分组,再按照组进行排序、计算聚合值以及进行比较。
95. 排序
使用orderby运算符给查询的结果排序。
96.join运算符
使用join运算符在一个查询中查找多个集合中的相关数据。
97. 使用数据库
数据库是永久的、结构化的数据仓库。有许多不同类型的数据库,业务数据最常用的类型是关系数据库。
98. Entity Framework
Entity Framework是一组.NET类,表示C#对象和关系数据库之间的对象-关系映射。
99. 如何使用Code First创建数据
在Entity Framework中使用Code First,可以使用对象-关系映射,直接从C#类和集合中创建数据库。
100. 如何给数据库使用LINQ
LINQ to Entities可使用与创建数据相同的Entity Framework类,支持在数据库上运行强大的查询功能。
101. 如何导航数据库关系
Entity Framework允许在数据库中通过使用C#代码中的虚拟属性和集合,创建和导航相关的实体。
102. 如何在数据库中创建和查询XML
可在单个查询中结合LINQ to Entities、LINQ to Objects和LINQ to XML,在数据库中构建XML。
祝您学习愉快!