-
Notifications
You must be signed in to change notification settings - Fork 3
/
C#.txt
1534 lines (1098 loc) · 82.3 KB
/
C#.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#.NET
##简介
> .NET Framework是一个集成在Windows中的组件,支持生成和运行下一代应用程序与 XML Web Services。
> .NET Framework具有两个主要组件:公共语言运行时(CLR)和.NET Framework类库。
目标是为了: 对各种代码提供了一致的面向对象的编程环境
##框架概貌
##CLR Common Language Runtime
> CLR在执行时是管理代码的代理,提供内存管理、线程管理和远程处理等核心服务,并且还强制实施严格的类型安全,以及可提高安全性和可靠性等其他形式的代码准确性。
> 代码管理概念是CLR的基本原则。以CLR为目标的代码称为托管代码,反之称为非托管代码。
##CLS Common language Specifications
> CLS规则定义了一个通用类型系统子集,即所有适用于CTS的规则都适用于CLS,除非CLS中定义了更严格的规则。
> CLS增强和确保了语言互用性
##通用类型系统
> 通用类型系统定义了如何在公共语言运行时中声明、使用和管理类型,同时也是运行时跨语言集成支持的一个重要组成部分
> 呈现在程序员面前的是不同语言的类型形式,.NET编译后它们都被转化为各自对应的内部类型,即各种类型所对应的基元数据类型。
##元数据和自描述组件
> 元数据是一种二进制信息,用以描述存储在CLR中的可移植可执行文件(PE)或存储在内存中的程序
元数据以非特定语言方式描述在代码中定义的每个类型和成员。元数据存储以下信息:
1. 程序集的说明
1. 类型的说明
1. 成员
1. 特性
##特性
> 元数据以非特定语言方式描述在代码中定义的每个类型和成员。元数据存储以下信息
> 特性与程序实体关联后,即可在运行时使用名为“反射”的技术查询特性
> C# 中,特性的指定方法为:将括在方括号中的特性名置于其应用到的实体的声明上方
若要显式标识特性目标,请使用下面的语法:[target : attribute-list]
其中target可选:
1. assembly
1. module
1. field
1. event
1. method
1. param 方法参数或 set 属性访问器参数
1. property
1. return
1. type 结构、类、接口、枚举或委托
注意:
* 根据约定,所有特性名称都以单词“Attribute”结束,以便将它们与“.NET Framework”中的其他项区分。
* 但是,在代码中使用特性时,不需要指定 attribute 后缀。
##跨语言互操作性
> 语言互操作性是一种代码与使用其他编程语言编写的另一种代码进行交互的能力
###原理
> 通过指定和强制通用类型系统和提供元数据,CLR为语言互操作性提供了必要基础
> 编译器将类型信息存储为元数据,CLR使用该信息在执行过程中提供服务;因为所有类型信息都以相同方式存储和检索,与编写该代码的语言无关,所以运行时可以管理多语言应用程序的执行
##程序集
> 程序集是.NET Framework应用程序的构造块;程序集构成了部署、版本控制、重复使用、激活范围控制和安全权限的基本单元
> 程序集是为协同工作而生成的类型和资源的集合,这些类型和资源构成了一个逻辑功能单元
> 程序集以可执行 (.exe) 文件或动态链接库 (.dll) 文件的形式出现,是 .NET Framework 的生成块
> 程序集可以是静态的或动态的,动态程序集直接从内存运行并且在执行前不存储到磁盘上;动态程序集执行后可保存在磁盘上
> 由于程序集包含有关内容、版本控制和依赖项的信息,因此用 C# 创建的应用程序不依赖注册表值就可正常运行
###程序集功能
1. 包含CLR执行的代码
1. 程序集形成安全边界
1. 程序集形成类型边界
1. 程序集形成引用范围边界
1. 程序集形成版本边界
1. 程序集形成部署单元
1. 程序集是支持并行执行的单元
###程序集清单
1. 程序集的标识(其名称和版本)
1. 文件表,描述组成程序集的所有其他文件
1. 程序集引用列表
##应用程序域
> 应用程序域为安全性、可靠性、版本控制以及卸载程序集提供了隔离边界
> 应用程序域通常由运行时宿主创建,运行时宿主负责在应用程序运行前引导CLR
##运行时宿主
> 每种应用程序都需要一个运行时宿主来启动它
> 运行时宿主加载运行时到进程中,在该进程内创建应用程序域,加载用户代码到该应用程序域
##.NET Framework类库
> .NET Framework类库是类、接口和值类型的库,提供对系统功能的访问。
###命名约定
> .NET Framework类型使用隐含层次结构的点语法命名方案
> 但是,此命名方案对可见性、成员访问、继承、安全性或绑定无效。
###命名空间
> 应用程序代码容器,唯一标示代码机器内容
> 一个命名空间可以被划分在多个程序集中,而单个程序集可以包含来自多个命名空间的类型
库开发人员在创建命名空间的名称时应使用以下原则:
*公司名称.技术名称*
global 命名空间是“根”命名空间:`global::System`始终引用 .NET Framework 命名空间 System
##性能
1. 如果必须频繁地将值类型装箱,则最好避免使用值类型
1. 在连接大量字符串变量时,例如在紧凑循环中,请使用 System.Text.StringBuilder
1. 不应使用空析构函数
##序列化
> 序列化是将对象处理为字节流以存储对象或传输到内存、数据库或文件
> 主要目的是保存对象的状态,以便可以在需要时重新创建对象。 相反的过程称为反序列化
> 在数据储与传送的部分是指将一个对象存储至一个储存媒介,例如档案或是记亿体缓冲等,或者透过网络传送资料时进行编码的过程,可以是字节或是XML等格式。而字节的或XML编码格式可以还原*完全相等*的对象。这程序被应用在不同应用程式之间传送对象,以及服务器将对象储存到档案或数据库
###二进制序列化
使用二进制编码来生成精简的序列化,以用于存储或基于套接字的网络流等
> 在二进制序列化中,会序列化所有成员(甚至包括那些只读成员),从而可以提高性能
###XML序列化
XML 序列化将对象的公共字段和属性或者方法的参数及返回值序列化为符合特定 XML 架构定义语言 (XSD) 文档的 XML 流
> 提供了可读性更好的代码,并在对象共享和使用方面提供了更大的灵活性,以便实现互操作性
> XML 序列化还可用于将对象序列化为符合 SOAP 规范的 XML 流
> 可以通过两种方式执行序列化:基本序列化和自定义序列化
1. 基本序列化使用 .NET Framework 来自动序列化对象
基本序列化的唯一要求是对象必须应用 SerializableAttribute 特性
> 使用基本序列化时,对象的版本控制可能会产生问题,在这种情况下,自定义序列化可能更合适
1. 自定义序列化
在自定义序列化中,可以准确地指定将序列化哪些对象以及如何完成序列化。 类必须标记为 SerializableAttribute,并实现 ISerializable 接口
1. 设计器序列化
设计器序列化是一种特殊形式的序列化,它涉及通常与开发工具关联的对象持久性的种类,是将对象图转换为以后可用于恢复对象图的源文件的过程
> 源文件可以包含代码、标记,甚至包含 SQL 表信息
##线程处理
> 线程处理解决了吞吐量和响应性的问题,但同时也带来了资源共享问题
> 多线程特别适用于需要不同资源(例如文件句柄和网络连接)的任务。 为单个资源分配多个线程可能会导致同步问题
##调用方信息
> 使用调用方信息属性,可以获取关于调用方的信息传递给方法
> 可以获取源代码、行号在源代码和调用方的成员名称的文件路径
---
#Visual C\# and C \#
##概述
> C#(读作“C sharp”)是一种编程语言,它是为生成在.NET Framework上运行的各种应用程序而设计的
> Visual C#是Microsoft对C#语言的实现,Microsoft Visual C#是美国微软公司开发的C#编程语言规格之集成开发环境使用者接口
> 实际上一般所说的Visual C#更多的是指微软所开发的,用于编写、编译、调试C#程序的集成开发环境
##C\#与.Net Framework
> C#程序在.NET Framework上运行
编译:
1. 用C#编写的源代码被编译为一种符合CLI规范的中间语言(IL)
1. IL代码与资源(例如位图和字符串)一起以一种称为程序集的可执行文件形式存储在磁盘上,通常具有扩展名.exe或.dll
1. 程序集包含清单,提供有关程序集的类型、版本、区域性和安全要求等信息
执行:
1. 执行C#程序时,程序集将加载到CLR中,根据清单中的信息可能会执行不同的操作
1. 然后,如果符合安全要求,CLR就会执行实时(JIT)编译以将IL代码转换为本机机器指令
1. CLR还提供与自动垃圾回收、异常处理和资源管理有关的其他服务
##C\#语言规范
###Main方法
> Main方法是控制台或windows应用程序(库和服务不需要它作为入口点)的程序入口点,控制程序流的开始和结束;应用程序开始时,首先调用它
> 在C#程序中,必须且只能有一个Main方法。如果有多余一个Main方法,编译程序时需要用/main编译选项指定哪个Main方法作为入口点
> Main方法是在类或结构内声明的static方法,不应该是public的,默认访问级别是private,不要求其所在类或结构是静态的。可返回void或int,也可带有参数
> Main方法的参数args是一个string型的数组,包含用于激活程序的命令行参数,程序中可接受这些参数控制程序运行或提供输入输出目标
> 与C++不同,数组不包含可执行(exe)文件的文件名d:\hello\hello
###I/O
####Console
> WriteLine方法是运行库中的Console类的输出方法之一,它在标准输出设备上输出字符串和一个新行:
> `System.Console.WriteLine("Hello World!");`
###类型
> C#是一种强类型语言。
类型中存储的信息包括:
1. 该类型的变量所需的存储空间
1. 该类型可以表示的最大值和最小值
1. 该类型包含的成员(方法、字段、事件等)
1. 该类型所继承的基类型
1. 将在运行时为其分配变量内存的位置
1. 允许的运算种类
> 编译器以元数据形式在可执行文件中嵌入类型信息
> CLR在运行期间使用元数据,以进一步保证在分配和回收内存时的类型安全
> 编译器会自动执行不引起数据损失的类型转换
> 可能导致数据损失的转换需要在源代码内有强制转换
> 可采用.NET Framework的GetType方法、Typeof操作符获取任何C#类型的实际类型,它们都返回System.Type对象
####变量
变量第一个字符必须为字母、下划线\_或@,其后续字符可以是数字、下划线或字母
1. camelCase :`firstName;timeOfDeath`
1. PascalCase :`WriteOfDiscontent`
####自定义类型
> 用户可使用struct、class、interface和enum结构创建自定义类型
####The Common Type System(CTS)
> 支持继承原则。类型可从称为基类型的其他类型派生
> CTS中的每个类型都被定义成值类型或引用类型
> 使用关键字struct定义的类型是值类型;所有内置数值类型都是struct
> 使用关键字class定义的类型是引用类型
####引用类型与值类型
> c#的简单类型、*结构*和*枚举*都属于值类型。类、代理、数组和接口属于引用类型
#####引用类型
> 引用类型包括类(class)、接口(interface)、数组(array)、委托(delegate)、object和字符串(string)
> null 是引用类型变量的默认值
> 还包括不提倡使用的指针类型
> 引用类型的变量称为对象,而值类型的变量仍然称为变量
> 但是请注意在本质上,一切类型产生的实例都是对象,C#是完全面向对象的
> 创建对象时,在托管堆上分配内存,变量只保存对象位置的引用
> 引用类型完全支持继承。创建类时,可以从任何非sealed的接口或类继承,而其他类则也可从您创建的类继承并重写虚方法
#####值类型
值类型的基类为System.ValueType
> 值数据类型的变量在传递的时候,传递的是数据的值;引用数据类型的变量在传递的时候,传递数据的地址
> 值类型不能包含null值,但可为null的值类型允许赋null值
1. SByte,表示8位有符号整数,System.SByte。SByte类型不符合CLS。符合CLS的替代类型是Int16
1. Byte,无符号 8 位整数,System.Byte
1. short,有符号 16 位整数,System.Int16
1. ushort,16位无符号整数,System.UInt16.UInt16类型不符合CLS。符合CLS的替代类型是Int32
1. int,有符号32位整数,System.Int32
1. uint,有符号32位整数,System.UInt32
1. long,64位有符号的整数,System.Int64
1. Ulong,无符号 64 位整数,System.UInt64
1. char,16 位 Unicode 字符,System.Char
1. String,String对象是Char结构的序列集合,用于表示文本字符串,System.String
1. \转义序列
\u Unicode 转义序列 \u0041 = "A"
\x Unicode 转义序列类似于“\u”,只是长度可变。 \x0041 = "A"
1. Unicode转义序列
1. @字符引导字符串
1. 格式字符串
`{index[,length][:formatString]}`
> 在内部,文本被存储为 Char 对象的顺序只读集合
> 字符串的 Length 属性代表它包含的 Char 对象的数量,而不是 Unicode 字符的数量
> 在 C# 中,string 关键字是 String 的别名。因此,String 与 string 等效
> 使用 Empty 常量值初始化字符串可新建字符串长度为零的 String 对象
> 字符串对象是不可变的:即它们创建之后就无法更改。所有看似修改字符串的 String 方法和 C# 运算符实际上都以新字符串对象的形式返回结果
1. float,一个单精度单精度32位浮点数字,System.Single
1. double,存储64位浮点值的简单类型,System.Double
1. decimal,128位数据类型,System.Decimal
1. bool,布尔值,System.Boolean
1. struct
struct类型是一种**值类型**,通常用来封装小型相关变量组,结构在表示简单数据类型组成的元素时,相对类而言具有更好的执行性能,可以视为轻量级的类
结构可包含构造函数、常量、字段、方法、属性、索引器、运算符、事件和嵌套类型
> 结构可以实现接口,其方式同类完全一样
> 一个结构不能从另一个结构或类继承,而且不能作为一个类的基,所有结构都直接继承自System.ValueType
> 从程序执行效率方面考虑,结构适合描述轻量级的、不包含引用数据类型的对象
*注意:*
1. 结构成员无法声明为protected
1. 在结构声明中,除非字段被声明为const或static,否则无法初始化
1. 结构不能声明默认构造函数(即无参构造函数)或析构函数,但可声明带参数的构造函数,为结构成员提供初始化的方法,使用new关键字调用默认构造函数创建结构实例时,结构中的字段均未赋值,不使用new关键字可以创建结构的实例,效果与使用默认结构函数创建结构实例相同
1. 在初始化所有字段之前,字段将保持未赋值状态且对象不可用;当结构包含引用类型作为成员时,必须显式调用该成员的默认构造函数,否则该成员将保持未赋值状态且该结构不可用
1. enum
> 枚举类型(也称为枚举),是由一组称为枚举数列表的命名常量组成的独特类型。可给变量赋值
> 每种枚举类型都有基础类型,该类型是除char以外的任何整型,
> enum进行类型转换时,即使orientation的基本类型是byte,仍必须使用(byte)强制类型转换,如果要将byte类型转换为orientation,也同样需要进行显式转换
> 应用System.FlagsAttribute特性,枚举类型可用来定义位标志
`[Flags]enum Days2 {...}`
`Days2 meetingDays = Days2.Tuesday | Days2.Thursday;`
1. 使用None作为值为0标志枚举常量的名字
与String的转换,即获得枚举的字符串值:
1. `directionString = myDirection.ToString(); `
1. `(enumerationType)Enum.Parse(typeof(enumerationType), enumerationValueString); `
*注意:*
1. 创建枚举时不能定义方法,但可以使用扩展方法为枚举创建新方法
1. array
`<baseType>[] <name>; `
1. 多维数组,矩形数组:`<baseType>[,] <name>; `
1. 交错数组:`int[][] jaggedIntArray; `
*注意:*
1. array都可以使用foreach循环辩论,其中基本数组与多维数组都可以直接使用foreach逐个元素遍历,而交错数组只能遍历内部数组,必须嵌套foreach
####泛型类型
> 可以通过一个或多个类型参数来声明一个类型,这些类型参数作为实际类型(具体类型)的占位符,在创建该类型实例时客户端代码提供实际类型
####隐式类型
> 可以使用关键字var隐式类型化一个局部变量(非类成员)。该变量在编译时接收一个由编译器提供的类型
> 不能在同一语句中初始化多个隐式类型的变量
> 可以创建隐式类型的数组,数组实例的类型由数组初始化中指定的元素推断而来: `var a = new[] { 1, 10, 100, 1000 }; // int[]`
> C#不支持隐式类型的多维数组
####匿名类型
> 匿名类型提供了一种方便的方法,可用来将一组只读属性封装到单个对象中,而无需首先显式定义一个类型
> 匿名类型是直接从object派生的引用类型
> 匿名类型无法强制转换为除object以外的任何类型
> 匿名类型中的只读属性类型也由编译器推断
> 匿名类型是由一个或多个公共只读属性组成的“类”(class)类型。不允许包含其他种类的类成员,如方法或事件。
> 如果两个或更多个匿名类型以相同顺序拥有相同数量和种类的属性,则编译器会将这些匿名类型视为相同类型,它们将共享编译器生成的相同类型信息
> 匿名类型上的Equals和GetHashCode方法是根据属性的Equals和GetHashcode定义的
> 在将匿名类型分配给变量时,*必须使用var构造初始化该变量*,因为只有编译器能够访问匿名类型的基础名称
> 如果必须存储查询结果或者必须将查询结果传递到方法边界外部,请考虑使用普通的命名struct或class而非匿名类型, 匿名类型有*方法范围限制*
> 如果没有在匿名类型中指定成员名称,编译器会用初始化这些成员的属性来命名。但使用使用表达式来初始化的成员,必须指定成员名称
####可为NULL类型
可为 null 类型是 System.Nullable<T> 结构的实例
声明方式有两种:
1. System.Nullable<T> variable
1. T? variable
> T可以是包括struct在内的任何值类型;但不能是引用类型,引用类型已支持null值。
> 当可为null类型对象的值为非null时,装箱行为发生;对象值为null时,不进行装箱,或理解为装箱结果为null
> 可null类型需通过*强制转换*或*Value属性*转换为常规类型,当值为null时会抛出异常
可用于null类型的运算符
1. 两个可为null类型执行比较时,如果它们的值均为null,则相等比较(==)的计算结果为true,其他比较的结果为false
1. 如果两个中仅有一个为null,则不等于比较(!=)为true,其他比较的结果为false
#####?? operator
null合并运算符,用于定义可为null值的类型和引用类型的默认值
如果此运算符的左操作数不为null,则返回左操作数;否则返回右操作数
#####Nullable\<T\>结构
System.Nullable\<T\>
1. HasValue:当变量包含非null值时,HasValue属性返回True,其默认值为false
1. Value:Value的类型与基础类型相同,它没有默认值
#####Nullable类
System.Nullable
> 支持可为其分配null的值类型,使之象引用类型。无法继承此类
> Nullable类为Nullable<T>结构提供补充支持
####dynamic
> 该类型是一种静态类型,但dynamic类型对象会绕过静态类型检查(即编译时类型检查),改为在运行时解析这些操作
> 编译器不会对包含dynamic类型表达式的操作进行解析或类型检查;而是将有关该操作信息打包在一起,用于计算运行时操作;在运行时,将检查存储的信息,任何无效语句将导致运行时异常;
> 实际上,dynamic类型变量会被编译到类型object的变量中
> 类型dynamic只在编译时存在,运行时不存在
1. 在声明中,作为属性、字段、索引器、参数、返回值或类型约束的类型,见上例中的类ExampleClass
1. 在显式类型转换中,作为转换的目标类型
1. 在以类型充当值(如is运算符或as运算符右侧)或者作为typeof的参数成为构造类型的一部分
#####dynamic类型转换
> 动态对象和其他类型之间的转换非常简单。这使开发人员能够在动态和非动态行为之间切换
> 任何对象都可隐式转换为dynamic类型,隐式转换也可动态地应用于类型为dynamic的任何表达式
> 如果方法调用中的一个或多个参数具有类型dynamic,或者方法调用的接收方类型为dynamic,则会在*运行时(而不是在编译时)*进行重载解析
####Pointer Type
> 在不安全的上下文中,类型可以是指针类型、值类型或引用类型: `type* identifier;` `int* p1, p2, p3; // Ok`
> myType\* 类型的指针变量的值是 myType 类型的变量的地址
> 指针类型不继承 object,并且指针类型与 object 之间不存在转换
> 装箱和取消装箱不支持指针,指针可以为 null
1. -\>运算符,运算符将指针取值与成员访问组合在一起:`x->y等效于(*x).y`
1. fix语句,禁止垃圾回收器重定位可移动的变量,还可用于创建固定大小缓冲区
> C# 编译器只允许在 fixed 语句中分配指向托管变量的指针
> 执行完语句中的代码后,任何固定变量都被解除固定并受垃圾回收的制约
1. stackalloc,用于不安全的代码上下文中,以便在堆栈上分配内存块,仅在局部变量的初始值中有效
####栈和堆
> 值类型存储在程序的堆栈,引用类型存储在托管内存的堆
> 堆栈:每个程序都有自己的堆栈,其他程序是不能直接访问的,在程序的方法被调用时,所用的本地变量都放入程序的堆栈,调用完毕后,变量出栈并检索
> 堆:在程序运行的过程中,clr定期检查并清理堆中不能访问的变量,释放该变量占用的内存
> 两种类型的对象都是自动销毁的。基于值类型的对象是在超出范围时销毁;基于引用类型的对象则是在对该对象的最后一个引用被移除之后在某个不确定的时间销毁;
> 当CLR对值类型进行装箱时,会将该值包装到System.Object内部,再将后者存储在托管堆上
---
###类型转换
> 由于 C# 是在编译时静态类型化的,因此变量在声明后就无法再次声明,或者无法用于存储其他类型的值,除非该类型可以转换为变量的类型
1. 隐式转换
1. 显式转换
1. 用户定义转换
1. 使用帮助程序类转换
####隐式转换
> 扩大转换不会导致数据丢失,但可能导致精度损失;由于不会丢失数据,因此编译器可以透明或隐式地处理数据
> 对于引用类型,隐式转换始终存在于从一个类转换为该类的任何一个直接或间接的基类或接口的情况
> 这些类型的隐式转换规则是:任何类型A,只要其取值范围完全包含在类型B的取值范围内,就可以隐式转换为类型B
####显式转换
> 当确定转换的值不超出目标类型的取值范围后,可以明确要求编译器将数值从一种数值类型转换为另一种数据类型
#####checked、unchecked
`checked(<expression>) `
`unchecked(<expression>) `
#####值类型的显式转换
> 收缩转换,现有类型比目标类型具有更大的范围和更大的成员列表;由于可以导致数据丢失,因此编译器通常需要通过调用转换方法或使用强制转换运算符来进行显式转换;可能引发OverflowException
1. 将 decimal 值转换为整型时,该值将舍入为与零最接近的整数值。如果结果整数值超出目标类型的范围,则会引发 OverflowException
1. 将 double 或 float 值转换为整型时,值会被截断。如果该结果整数值超出了目标值的范围,其结果将取决于溢出检查上下文
1. 将 double 转换为 float 时,double 值将舍入为最接近的 float 值。如果 double 值因过小或过大而使目标类型无法容纳它,则结果将为零或无穷大
#####引用类型的显式转换
> 对于引用类型,如果需要从基类型转换为派生类型,则必须进行显式强制转换
> 引用类型之间的强制转换操作**不会更改基础对象的运行时类型**;它只更改用作对该对象的引用的值的类型
> 在某些引用类型转换中,编译器无法确定强制转换是否会有效。**正确进行编译的强制转换操作有可能在运行时失败**。类型强制转换在运行时失败将导致引发 InvalidCastException
####自定义转换
> 可在*类*或*结构*上声明自定义转换,以便类或结构与其他类或结构或者基本类型进行相互转换
> 声明为 implicit 的转换在需要时自动进行。声明为 explicit 的转换需要调用强制转换。所有转换都必须声明为 static
1. `public static implicit operator ByteWithSign(SByte value)`
1. `public static explicit operator ByteWithSign(int value)`
1. `static public explicit operator int(RomanNumeral roman)`//RomanNumeral转换为int
####IConvertible接口
> 定义特定的方法,这些方法将实现引用或值类型的值转换为具有等效值的公共语言运行时类型
> System.IConvertible,不兼容CLS
实现类型需要提供一下方法:
1. 返回实现类型的TypeCode方法
1. 用于将实现类型转换为CLR中的每种基类型(Boolean、Byte、DateTime、Decimal和Double等)的各种方法 `ToByte() ToDouble()...`
1. 用于将实现类型的实例转换为另一个指定类型的通用转换方法
> 不支持的转换应引发InvalidCastException
`int codePoint = 1067;
IConvertible iConv = codePoint;
char ch = iConv.ToChar(null);`
> CLR每种基类型都实现了该接口,也可以仅通过IConvertible接口变量来调用转换方法,但是开销更大
#####TypeCode 枚举
> System.TpyeCode,指定对象类型
`Object、DBNull、Char、Boolean`
> 在实现 IConvertible 接口的类上调用 GetTypeCode 方法,以获得类实例的类型代码
> 其他情况下,调用对象的 GetType 方法,以获得其 Type 对象,然后调用 Type 对象的 GetTypeCode 方法以获得该对象的类型代码;`Type.GetTypeCode( testObject.GetType())`
####Convert类
> System.Convert,将一个基本数据类型转换为另一个基本数据类型
> 虽然可以调用每个基类型的IConvertible接口实现来执行类型转换,但建议使用System.Convert类的方法,实现基类型间的转换,因为这种方式与语言无关
> Convert类提供了一种与语言无关的方式来执行基类型间的转换,并且该类可用于面向公共语言运行时的所有语言
> Convert类包含了所有基类型间相互转换的方法,因此不再需要调用每个基类型的IConvertible显式接口实现
#####基类型之间转换
1. 无转换。当尝试将一个类型转换为其本身时
1. 一个 InvalidCastException。当不支持特定转换时会发生这种情况
1. FormatException。当由于字符串格式不正确而导致将字符串值转换为任何其他基类型的尝试失败时,会发生该异常
1. 转换成功。对于前面结果中未列出的两个不同基类型之间的转换,所有扩大转换和不会导致数据丢失的收缩转换都将成功,此方法将返回目标基类型的值
1. 一个 OverflowException。当收缩转换导致数据丢失时会发生这种情况
#####区域性特定的格式设置信息
> 所有基类型转换方法和 ChangeType 方法都包括具有类型为 IFormatProvider 的参数的重载
> IFormatProvider 参数可以提供区域性特定的格式设置信息以帮助转换过程
#####从自定义对象转换为基类型
> 自定义类型必须实现 IConvertible 接口,该接口定义用于将实现类型转换为每个基类型的方法
> 向 ChangeType 方法传递自定义类型作为其第一个参数时,或者在调用 Convert.ToType方法(如 Convert.ToInt32(Object) 或Convert.ToDouble(Object, IFormatProvider))并向其传递自定义类型的实例作为其第一个参数时,Convert 方法反过来会调用自定义类型的 IConvertible 实现以执行转换
####自定义类型转换
NET Framework 提供以下两种机制来将用户定义数据类型(自定义类型)转换为其他数据类型:
1. 通过扩展 System.ComponentModel.TypeConverter 类为自定义类型定义类型转换器,并通过 System.ComponentModel.TypeConverterAttribute 特性使类型转换器与类型关联
* 在设计时和运行时都可以使用
* 使用反射,因此比 IConvertible 所支持的转换慢
* 允许自定义类型和其他数据类型间的双向类型转换。
* 类型的 TypeConverter 在类型的外部实现,并通过应用 TypeConverterAttribute 特性与该类型关联
1. 对自定义类型实现 System.IConvertible 接口
* 只能在运行时使用
* 不使用反射
* 允许从自定义类型转换为其他数据类型,但不允许从其他数据类型转换为自定义类型
* IConvertible 由自定义类型实现。为转换类型,类型的用户对类型调用转换方法(属于 IConvertible 协定)
#####TypeConverter 类
System.ComponentModel.TypeConverter,提供一种将值的类型转换为其他类型以及访问标准值和子属性的统一方法
####类型转换相关操作符
#####()Operator
用来指定表达式的运算顺序,强制类型转换,调用方法或委托;`a = (int)x;`
> 可用explicit和implicit来定义转换运算符。不能重载()运算符
#####is操作符
Is操作符检查对象是否与给定类型兼容;`o is Class1;`
> 不能重载is运算符,is运算符只考虑引用转换、装箱转换和取消装箱转换,不考虑其他转换,如用户定义的转换
> 在is运算符的左侧不允许使用匿名方法,lambda表达式属于例外
#####as运算符
as运算符用于在兼容的引用类型之间执行类型转换。语法为:`expression as type`
它等效于以下表达式,但只计算一次expression。`expression is type ?(type)expression : (type)null`
> as运算符之后不被不能是值类型数据类型,即该运算符不支持值类型对象的转换,否则将会引起编辑错误
> as运算符类似于强制转换操作,但非真正的强制转换,如基类对象到其派生类的类型转换,as将返回null
> as运算符用于引用类型的转换和值类型的装箱,无法执行其他转换,如用户定义的转换,这类转换应使用强制转换表达式来执行
> as运算符支持值类型数据到object类型的转换,这时对值类型遍历进行的是一个装箱操作
#####转换运算符设计指南
1. 如果最终用户未明确要求此类转换,则不要提供相应的转换运算符
1. 不要在类型域之外定义转换运算符;如果要将一种类型转换为不同域中的另一种类型,请使用构造函数
1. 如果转换可能丢失信息,则不要提供隐式转换运算符
1. 不要在隐式强制转换中引发异常
---
###C#运算符
1. 普通运算符
1. . 运算符,用于成员访问
1. () 运算符,用于指定表达式中运算符的顺序+指定强制转换或类型转换
1. 方括号 ([]) 用于数组、索引器和特性,也可用于指针
1. 递增运算符 (++) 将操作数加 1
* 前缀增量操作。操作结果是操作数加 1 之后的值
* 后缀增量操作。运算结果是操作数增加之前的值
1. 递减运算符 (--) 将操作数减 1。递减运算符可出现在操作数之前或之后
1. + - \* / %
1. 关系和类型运算符;`>` `<` `>=` `<=` `is` `as`
1. 相等运算符;`==` `!=`
1. 位运算符
1. 一元 + 运算符是为所有数值类型预定义的;对数值类型进行一元 + 运算的结果就是操作数的值
1. 一元 - 运算符是为所有数值类型预定义的。数值类型的一元 - 运算的结果是操作数的反数
1. 逻辑非运算符 (!) 是对操作数求反的一元运算符。为 bool 定义了该运算符,当且仅当操作数为 false 时才返回 true
1. ~ 运算符对操作数执行按位求补运算,其效果相当于反转每一位
1. 一元 & 运算符返回操作数的地址(要求 unsafe 上下文)
1. 左移运算符 (\< \< ) 将第一个操作数向左移动第二个操作数指定的位数
1. 右移运算符 (\> \> ) 将第一个操作数向右移动第二个操作数所指定的位数
1. 逻辑、条件和 null 运算符
1. x & y,逻辑“与”
1. x ^ y,逻辑“异或”
1. x | y,逻辑“或”
1. x && y,条件“与”,与&区别在于性能好,若x为false则不计算y
1. x || y,条件“或”,与|区别在于性能好,若x为true则不计算y
1. X ?? y,Null 合并,如果 x 为 Null 则计算结果为 y,否则计算结果为 x
1. x ? y : z,如果 x 为 True 则计算结果为 y,如果 x 为 False 则计算结果为 z
1. 赋值和匿名运算符
1. =,赋值
1. x op= y ,复合赋值,支持的运算符包括:+=、-=、\*=、/=、%=、&=、|=、!=、\< \< =、\> \> =
1. (T x) => y ,匿名函数(lambda 表达式)
> => 运算符具有与赋值运算符 (=) 相同的优先级,并且是右结合运算符
1. :: 运算符
命名空间别名限定符 (::) 用于查找标识符。它通常放置在两个标识符之间
1. 特殊运算符
1. as,将对象转换为可兼容类型
1. is,检查对象的运行时类型
1. new,new 运算符:创建对象/new 修饰符:隐藏继承成员/new 约束:限定类型参数
1. sizeof,获取类型的大小
1. typeof,获取类型的 System.Type 对象
typeof运算符的操作数是类或数据类型,而不是类的实例或者变量
1. true/false
1. stackalloc,在堆栈上分配内存块
1. checked/unchecked
####运算符重载
> 对用户定义的类型,通过使用 operator 关键字定义静态成员函数来重载运算符
---
###C#语法
C#是case-sensitive的
####注释
1. `/* comments */`
2. `//comments`
3. `///comments`
####分支
1. 三元运算符
`<test> ? <resultIfTrue>: <resultIfFalse> `
1. if语句
`if (<test>)
<code executed if <test> is true>;
else if
<code executed if <test> is false>;
`
1. switch语句
`switch (<testVar>)
{
case <comparisonVal1>: //其中comparisonVal1可以为常数或常量
<code to execute if <testVar> == <comparisonVal1> >
break;
default:
<code to execute if <testVar> != comparisonVals>
break;
`
> 如果把多个case 语句放在一起(堆叠它们),其后加一个代码块,实际上是一次检查多个条件。如果满足这些条件中的任何一个,就会执行代码,比如:
`case <comparisonVal1>:
case <comparisonVal2>:
<code to execute if <testVar> == <comparisonVal1> or
<testVar> == <comparisonVal2> >
break; `
> 也可以使用goto,语句(如前所述),因为case语句实际上是在C#代码中定义的标签
> 每个\<comparisonValX\>都必须是一个常数值
####循环
1. do循环
`do
{
<code to be looped>
} while (<Test>);
`
1. while循环
`while (<Test>)
{
<code to be looped>
}
`
1. for循环
`
for (<initialization>; <condition>; <operation>)
{
<code to loop>
}
`
1. foreach循环
`foreach (<baseType> <name> in <array>)
{
// can use <name> for each element
}`
注意:
1. foreach循环对数组内容进行只读访问,所以不能改变任何元素的值
#####循环的中断
1. break 立即终止循环
1. continue 立即终止当前的循环
1. goto
使用goto语句从外部进入循环是非法的
1. return 跳出循环及其包含的函数
1. throw 用于发出在程序执行期间出现反常情况(异常)的信号
1. lock 将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁
可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区
其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放
####命名空间
> 它们是.NET中提供应用程序代码容器的方式,这样就可以唯一地标识代码及其内容。名称空间也用作.NET Framework中给项分类的一种方式
#####namespace
> 根据约定,名称空间通常采用PascalCase命名方式。
`namespace LevelOne`
> 可嵌套,不同的命名空间级别之间使用句点字符(.)
#####using
> 创建了名称空间后,即可使用using语句简化对它们所含名称的访问 `using LevelTwo;`
> 可以使用using语句为名称空间提供一个别名 `using LT = LevelTwo;`
####goto语句
C#允许给代码行加上标签,这样就可以使用goto语句直接跳转到这些代码行上。该语句优缺点并存
> `goto <labelName>; ` `<labelName>: `
####lambda表达式
> Lambda表达式表示没有名称但可以具有输入参数和多个语句的“内联方法”
> “Lambda表达式”是一个匿名函数,它可以包含表达式和语句,并且可用于创建委托或表达式树类型
#####lambda语法
`(input parameters) => expression`
> 所有Lambda表达式都使用 Lambda 运算符 =>,该运算符读为“goes to”
> 在 is 或 as 运算符的左侧不允许使用 Lambda
> 适用于匿名方法的所有限制也适用于 Lambda 表达式
#####lambda语句
`(input parameters) => {statement;}`
> Lambda 语句的主体可以包含任意数量的语句
> 像匿名方法一样,Lambda 语句无法用于创建表达式树
1. Lambda 包含的参数数量必须与委托类型包含的参数数量相同
1. Lambda 中的每个输入参数必须都能够隐式转换为其对应的委托参数
1. Lambda 的返回值(如果有)必须能够隐式转换为委托的返回类型
####异常处理
在 .NET Framework 中,异常是从 System.Exception 类继承的对象
> 异常从发生问题的代码区域引发, 然后沿堆栈向上传递,直到应用程序处理它或程序终止
运行时实现的异常处理具有以下特点:
1. 处理异常时不用考虑该异常的生成或处理语言;
1. 异常处理时不要求任何特定的语言语法,而是允许每种语言定义自己的语法;
1. 允许跨进程甚至跨计算机边界引发异常
**运行时的异常处理模型是基于异常对象和受保护代码块:**
* 运行时为每个可执行文件创建一个异常信息表。在异常信息表中,可执行文件的每个方法都有一个关联的异常处理信息数组(可以为空)
* 数组中的每一项描述一个受保护的代码块、任何与该代码关联的异常筛选器和任何异常处理程序(catch 语句)
* 此异常表非常有效,仅在异常发生时使用资源;在没有异常发生时,它不会引起处理器时间或内存使用方面的任何性能损失
**异常信息表为受保护代码块提供了四种类型的异常处理程序:**
* finally 处理程序,每当“块”退出时它都会执行,不考虑退出是由正常控制流引起的还是由未经处理的异常引起。
* 错误处理程序,在异常发生时一定执行,但在正常控制流完成时不执行。
* 类型筛选的处理程序,它处理指定类或其派生类的任何异常。
* 用户筛选的处理程序,它运行用户指定的代码,来确定异常应由关联的处理程序处理还是应传递给下一个受保护的块。
> C# 不实现用户筛选的处理程序
**异常发生时,运行时分两步来处理:**
1.运行时在数组中搜索执行下列操作的第一个受保护块:
保护包含当前执行的指令的区域。
包含异常处理程序或包含处理异常的筛选器。
2.如果出现匹配项,则运行时会创建一个 Exception 对象来描述该异常。 然后运行时执行位于该异常的发生语句和处理语句之间的所有 finally 语句或错误语句
异常处理程序的顺序很重要;最里面的异常处理程序最先计算。
异常处理程序可以访问捕捉异常程序中的局部变量和本地内存,但异常发生时的任何中间值都会丢失。
#####异常处理
各种类型的异常最终都是由 System.Exception 派生而来。
> 除非可以处理某个异常并使应用程序处于已知状态,否则请不要捕捉该异常
> 如果捕捉 System.Exception,请在 catch 块的末尾使用 throw 关键字再次引发该异常
> 如果 catch 块定义了一个异常变量,则可以用它获取有关所发生异常类型的更多信息
> .NET Framework 中的托管异常是凭借 Win32 结构化异常处理机制实现的
* throw
* try-catch
* try-finally
* try-catch-finally
* try-catch
> 多个 catch 块的计算顺序是在代码中从顶部到底部;但对引发的每个异常,都只执行一个 catch 块
> 可在 catch 块中使用 throw 语句以重新引发已由 catch 语句捕获的异常(原异常) `throw;`
> try 块内部只初始化其中声明的变量。否则,完成对块的执行前,可能会发生异常
**引发异常时要避免的情况:**
1. 不应使用异常来更改正常执行过程中的程序流程。异常只能用于报告和处理错误条件
1. 只能引发异常,而不能作为返回值或参数返回异常
1. 不要从自己的源代码中有意引发 System.Exception、System.SystemException、System.NullReferenceException 或 System.IndexOutOfRangeException
1. 不要创建可在调试模式下引发但不会在发布模式下引发的异常。若要在开发阶段确定运行时错误,请改用调试断言
#####非 CLS 异常捕捉
1. 在 catch (Exception e) 块中作为 RuntimeWrappedException 捕捉
默认情况下,Visual C# 程序集将非 CLS 异常作为包装异常来捕捉。
如果需要,可通过 WrappedException 属性访问原始异常
1. 在位于 catch (Exception) 或 catch (Exception e) 块之后的常规 catch 块(没有指定异常类型的 catch 块)中
如果要执行某个操作(如写入日志文件)以响应非 CLS 异常,并且不需要访问异常信息,请使用此方法
#####using语句
提供能确保正确使用 IDisposable 对象的方便语法
> 当使用 IDisposable 对象时,应在 using 语句中声明和实例化此对象
> using 语句按照正确方式调用对象的 Dispose 方法,并会导致对象自身处于范围之外
> 在 using 块中,对象是只读的并且无法进行修改或重新分配
> **通过将对象放入 try 块中,并在 finally 块中调用Dispose,可以获得相同的结果;实际上,这就是编译器转换 using 语句的方式**
#####Exception
System.Exception 是异常的基类。 若干个异常类直接从 Exception 继承,其中包括
1. 从 SystemException 派生的预定义公共语言运行时异常类。
1. 从 ApplicationException 派生的用户定义的应用程序异常类。
这两个类构成几乎所有运行时异常的基础
######SystemException
System.SystemException,为 System 命名空间中的预定义异常定义基类
> 此类是作为一种方法提供的,用于区分系统定义的异常和应用程序定义的异常
######ApplicationException
System.ApplicationException,发生非致命应用程序错误时引发的异常
> 用户应用程序(不是公共语言运行时)引发从 ApplicationException 类派生的自定义异常
> ApplicationException 类区分应用程序定义的异常与系统定义的异常
> 应从 Exception 类派生自定义异常,非从ApplicationException 类派生
SystemException 使用值为 0x80131501 的 HRESULT COR_E_SYSTEM
####预处理指令
1. 第一种用来描述代码段区间,
1. 第二种在指定的条件下忽略代码段,
1. 第三种用来报告错误和指定警告的条件
> C#编程语言的预处理指令不包含宏、而且必须是当前行中唯一的指令
#####条件指令
条件预处理指令包含一组预处理指令,分别是if预处理指令、elif预处理指令、else预处理指令和endif预处理指令
1. #if、#else、#endif、#elif
1. #define、#undef
define预处理指令用于定义一个符号,该符号可用于if预处理指令的判断条件
与define预处理相反的指令是undef预处理指令,undef预处理指令用于取消符号的定义
> 用/define 或 #define定义的符号与同名变量不抵触,即,变量名不能传给预处理指令,符号仅能在预处理指令中使用
1. #warning、#error
warning预处理指令在代码的当前位置生成一个警告。在一些特殊的场合中,用来作为比较显眼的警示。
error预处理指令在代码的当前位置生成一个错误,该预处理指令有效时,程序不能编译执行。
1. #line
#line lets you modify the compiler's line number and (optionally) the file name output for errors and warnings.
1. The #line hidden directive hides the successive lines from the debugger, such that when the developer steps through the code, any lines between a #line hidden and the next #line directive (assuming that it is not another #line hidden directive) will be stepped over.
> A #line hidden directive does not affect file names or line numbers in error reporting. That is, if an error is encountered in a hidden block, the compiler will report the current file name and line number of the error.
1. The #line filename directive specifies the file name you want to appear in the compiler output. By default, the actual name of the source code file is used. The file name must be in double quotation marks ("")
1. #region、endregion
region除了定义代码区间,通过在编辑器显示大纲的折叠和展开方便阅读代码以外,还具备注释功能,在其后可以跟随代码区间的描述语句
> 注释语句将作为region的一部分,不能称为独立的注释语句。而endregion后面可以加入独立的注释语句
1. #pragma
#pragma gives the compiler special instructions for the compilation of the file in which it appears : `#pragma pragma-name pragma-arguments`
1. #pragma warning
#pragma warning can enable or disable certain warnings: `#pragma warning disable warning-list` or `#pragma warning restore warning-list`
1. #pragma checksum
Generates checksums for source files to aid with debugging ASP.NET pages : `#pragma checksum "filename" "{guid}" "checksum bytes"`
####LINQ
所有 LINQ 查询操作都由以下三个不同的操作组成:
1. 获取数据源。
LINQ 数据源是支持泛型 IEnumerable<T> 接口或从该接口继承的接口的任意对象
1. 创建查询。
在 LINQ 中,查询变量本身不执行任何操作并且不返回任何数据。 它只是存储在以后某个时刻执行查询时为生成结果而必需的信息
查询变量本身只是存储查询命令。 实际的查询执行会延迟到在 foreach 语句中循环访问查询变量时发生。 此概念称为“延迟执行”
1. 执行查询。
####类与类成员
类和结构是 .NET Framework 中的常规类型系统的两种基本构造。
两者在本质上都属于数据结构,封装着一组整体作为一个逻辑单位的数据和行为
> 类是一种引用类型。 创建类的对象时,对象赋值到的变量只保存对该内存的引用
> 结构是一种值类型。 创建结构时,结构赋值到的变量保存该结构的实际数据
**“封装”有时被称为面向对象的编程的第一个支柱或原则**
根据封装的原则,类或结构可以指定其每个成员对于该类或结构外部的代码的可访问性
**类(而非结构)支持继承的概念**
派生自另一个类(“基类”)的类将自动包含基类除构造函数和析构函数之外的所有公共、受保护和内部成员
**类和结构可以继承多个接口**
从接口继承意味着该类型要实现该接口中定义的所有方法
#####创建对象
1. 通过使用 new 关键字(后跟类名称)可以创建对象
1. 使用对象初始值设定项可以在创建对象时向对象的任何可访问的字段或属性分配值,而无需显式调用构造函数
如果只想存储某个序列中每个对象的部分信息,这会有用:
`var productInfos =
from p in products
select new {p.ProductName, Price = p.UnitPrice};`
1. 在初始化实现了IEnumerable 接口的集合类时,使用集合初始值设定项可以指定一个或多个元素的初始值设定项
#####访问修饰符
1. public
1. private
1. protected
1. internal
1. protected internal
访问仅限于从包含类派生的当前程序集或类型
> 直接在命名空间中声明的类和结构和接口,可以是公共类和结构和接口,也可以是内部类和结构和接口.**如果不指定访问修饰符,则默认为 internal**
> 结构成员,包括嵌套的类和结构,可以声明为公共的、 内部的,或私人的。**因为结构不支持继承**
> 类成员(包括嵌套的类和结构)可以为公共的、受保护的内部、受保护的、内部的或私有的。
> 类成员和结构成员的访问级别,包括嵌套类和结构,**默认为私有**。不可以从包含类型之外访问私有嵌套类型
> 派生类的可访问性不能高于其基类型
> 任何成员(字段、 属性或事件)的类型必须至少与该成员本身一样具备可访问性
> 任一成员(方法、索引器或委托)的返回类型和参数类型必须至少有与该成员本身一样的可访问性
> 用户定义的运算符必须始终声明为公共运算符。
> **析构函数不能具有可访问性修饰符**
> 接口成员始终是公共成员;枚举成员始终是公共的,不能应用任何访问修饰符
> 委托行为类似于类和结构。默认情况下,它们在命名空间中直接声明时具有内部访问权,在嵌套时具有私有访问权
#####字段
类或结构可以拥有实例字段或静态字段,或同时拥有两者
> 存储由公共属性公开数据的私有字段称为“后备存储”或“支持字段”
> 字段的初始化紧靠调用对象实例的构造函数之前。
> 如果构造函数为字段赋值,则该值将覆盖字段声明期间给出的任何值
> 1. 如字段声明为 static,则调用方在任何时候都能使用字段,即使类没有任何实例
> 1. 如字段声明为 readonly,只读字段只能在初始化期间或在构造函数中赋值
#####常量
常量是在编译时已知并在程序的生存期内不发生更改的不可变值
######const
> 常数表达式是在编译时可被完全计算的表达式;只有 C# 内置类型(System.Object 除外)可以声明为 const;可以使用枚举类型为整数内置类型(例如 int、uint、long 等等)定义命名常量
> C# 不支持 const 方法、属性或事件
> 因为常量值对该类型的所有实例是相同的,所以常量被当作 static 字段一样访问
######readonly
readonly 修饰符创建在运行时初始化一次即不可再更改的类、结构或数组
> 虽然 const 字段是编译时常量,但 readonly 字段可用于运行时常量: `public static readonly uint l1 = (uint)DateTime.Now.Ticks;`
**readonly 字段的赋值:**
1. 在声明中初始化变量,如: `public readonly int y = 5;`
2. 对实例字段,可用声明该字段类中的实例构造函数对其进行赋值;
3. 对静态字段,在包含字段声明的类的静态构造函数中对其进行复制
> 也仅在上述环境中,将 readonly 字段作为 out 或 ref 参数传递才有效
#####构造函数
1. 默认构造函数
不带参数的构造函数称为“默认构造函数”
> 声明空构造函数可阻止自动生成默认构造函数
1. 私有构造函数
通过将构造函数设置为私有构造函数,可以阻止类被实例化
它通常用在只包含静态成员的类中
1. 结构类型的构造函数
与类的构造函数类似,但是 structs 不能包含显式默认构造函数,因为编译器将自动提供一个构造函数
1. 有参构造函数
类和 structs 都可以定义具有参数的构造函数
> 带参数的构造函数必须通过 new 语句或 base 语句来调用
1. 复制构造函数
与有些语言不同,C# 不提供复制构造函数。 如果需要,必须自行编写适当方法
######base
**base 关键字用于从派生类中访问基类的成员:**
1. 调用基类上已被其他方法重写的方法。
1. 指定创建派生类实例时应调用的基类构造函数
> 从静态方法中使用 base 关键字是错误的