c# language specification - ecma international shar… · web viewthis international standard is...
TRANSCRIPT
C# Language Specification
C#
Language Specification
Working Draft WD3.10
May 20 2016
Table of Contents
Forewordxix
Introductionxx
1. Scope1
2. Conformance3
3. Normative references5
4. Terms and definitions7
5. Acronyms and abbreviations13
6. General description15
7. Language overview17
7.1 General17
7.2 Hello world17
7.3 Program structure18
7.4 Types and variables20
7.5 Expressions22
7.6 Statements25
7.7 Classes and objects29
7.7.1 General29
7.7.2 Members30
7.7.3 Accessibility30
7.7.4 Type parameters31
7.7.5 Base classes31
7.7.6 Fields32
7.7.7 Methods32
7.7.7.1 General32
7.7.7.2 Parameters33
7.7.7.3 Method body and local variables34
7.7.7.4 Static and instance methods34
7.7.7.5 Virtual, override, and abstract methods35
7.7.7.6 Method overloading37
7.7.8 Other function members38
7.7.8.1 General38
7.7.8.2 Constructors39
7.7.8.3 Properties40
7.7.8.4 Indexers40
7.7.8.5 Events41
7.7.8.6 Operators41
7.7.8.7 Finalizers42
7.8 Structs42
7.9 Arrays43
7.10 Interfaces44
7.11 Enums46
7.12 Delegates47
7.13 Attributes48
8. Lexical structure51
8.1 Programs51
8.2 Grammars51
8.2.1 General51
8.2.2 Grammar notation51
8.2.3 Lexical grammar53
8.2.4 Syntactic grammar54
8.2.5 Grammar ambiguities54
8.3 Lexical analysis55
8.3.1 General55
8.3.2 Line terminators55
8.3.3 Comments56
8.3.4 White space57
8.4 Tokens58
8.4.1 General58
8.4.2 Unicode character escape sequences58
8.4.3 Identifiers59
8.4.4 Keywords60
8.4.5 Literals62
8.4.5.1 General62
8.4.5.2 Boolean literals62
8.4.5.3 Integer literals62
8.4.5.4 Real literals63
8.4.5.5 Character literals64
8.4.5.6 String literals65
8.4.5.7 The null literal67
8.4.6 Operators and punctuators67
8.5 Pre-processing directives67
8.5.1 General67
8.5.2 Conditional compilation symbols69
8.5.3 Pre-processing expressions69
8.5.4 Definition directives70
8.5.5 Conditional compilation directives71
8.5.6 Diagnostic directives73
8.5.7 Region directives74
8.5.8 Line directives74
8.5.9 Pragma directives75
8.5.9.1 General75
8.5.9.2 Pragma warning76
9. Basic concepts77
9.1 Application startup77
9.2 Application termination79
9.3 Declarations79
9.4 Members83
9.4.1 General83
9.4.2 Namespace members83
9.4.3 Struct members84
9.4.4 Enumeration members84
9.4.5 Class members84
9.4.6 Interface members84
9.4.7 Array members85
9.4.8 Delegate members85
9.5 Member access85
9.5.1 General85
9.5.2 Declared accessibility85
9.5.3 Accessibility domains86
9.5.4 Protected access for instance members88
9.5.5 Accessibility constraints89
9.6 Signatures and overloading90
9.7 Scopes92
9.7.1 General92
9.7.2 Name hiding94
9.7.2.1 General94
9.7.2.2 Hiding through nesting94
9.7.2.3 Hiding through inheritance95
9.8 Namespace and type names96
9.8.1 General96
9.8.2 Fully qualified names99
9.9 Automatic memory management100
9.10 Execution order102
10. Types105
10.1 General105
10.2 Value types105
10.2.1 General105
10.2.2 The System.ValueType type106
10.2.3 Default constructors106
10.2.4 Struct types107
10.2.5 Simple types107
10.2.6 Integral types108
10.2.7 Floating-point types109
10.2.8 The decimal type111
10.2.9 The bool type111
10.2.10 Enumeration types112
10.2.11 Nullable value types112
10.3 Reference types112
10.3.1 General112
10.3.2 Class types113
10.3.3 The object type114
10.3.4 The dynamic type114
10.3.5 The string type114
10.3.6 Interface types114
10.3.7 Array types114
10.3.8 Delegate types114
10.4 Boxing and unboxing115
10.4.1 General115
10.4.2 Boxing conversions115
10.4.3 Unboxing conversions117
10.5 Constructed types119
10.5.1 General119
10.5.2 Type arguments119
10.5.3 Open and closed types120
10.5.4 Bound and unbound types120
10.5.5 Satisfying constraints120
10.6 Type parameters121
10.7 Expression tree types122
10.8 The dynamic type123
11. Variables125
11.1 General125
11.2 Variable categories125
11.2.1 General125
11.2.2 Static variables125
11.2.3 Instance variables125
11.2.3.1 General125
11.2.3.2 Instance variables in classes126
11.2.3.3 Instance variables in structs126
11.2.4 Array elements126
11.2.5 Value parameters126
11.2.6 Reference parameters126
11.2.7 Output parameters127
11.2.8 Local variables127
11.3 Default values128
11.4 Definite assignment128
11.4.1 General128
11.4.2 Initially assigned variables129
11.4.3 Initially unassigned variables129
11.4.4 Precise rules for determining definite assignment130
11.4.4.1 General130
11.4.4.2 General rules for statements130
11.4.4.3 Block statements, checked, and unchecked statements130
11.4.4.4 Expression statements131
11.4.4.5 Declaration statements131
11.4.4.6 If statements131
11.4.4.7 Switch statements131
11.4.4.8 While statements131
11.4.4.9 Do statements132
11.4.4.10 For statements132
11.4.4.11 Break, continue, and goto statements132
11.4.4.12 Throw statements132
11.4.4.13 Return statements132
11.4.4.14 Try-catch statements133
11.4.4.15 Try-finally statements133
11.4.4.16 Try-catch-finally statements133
11.4.4.17 Foreach statements134
11.4.4.18 Using statements134
11.4.4.19 Lock statements135
11.4.4.20 Yield statements135
11.4.4.21 General rules for simple expressions135
11.4.4.22 General rules for expressions with embedded expressions135
11.4.4.23 Invocation expressions and object creation expressions136
11.4.4.24 Simple assignment expressions136
11.4.4.25 && expressions137
11.4.4.26 || expressions137
11.4.4.27 ! expressions138
11.4.4.28 ?? expressions139
11.4.4.29 ?: expressions139
11.4.4.30 Anonymous functions139
11.5 Variable references141
11.6 Atomicity of variable references141
12. Conversions143
12.1 General143
12.2 Implicit conversions143
12.2.1 General143
12.2.2 Identity conversion144
12.2.3 Implicit numeric conversions144
12.2.4 Implicit enumeration conversions144
12.2.5 Implicit nullable conversions144
12.2.6 Null literal conversions145
12.2.7 Implicit reference conversions145
12.2.8 Boxing conversions146
12.2.9 Implicit dynamic conversions147
12.2.10 Implicit constant expression conversions147
12.2.11 Implicit conversions involving type parameters147
12.2.12 User-defined implicit conversions148
12.2.13 Anonymous function conversions and method group conversions148
12.3 Explicit conversions148
12.3.1 General148
12.3.2 Explicit numeric conversions149
12.3.3 Explicit enumeration conversions151
12.3.4 Explicit nullable conversions151
12.3.5 Explicit reference conversions151
12.3.6 Unboxing conversions152
12.3.7 Explicit dynamic conversions153
12.3.8 Explicit conversions involving type parameters154
12.3.9 User-defined explicit conversions155
12.4 Standard conversions155
12.4.1 General155
12.4.2 Standard implicit conversions155
12.4.3 Standard explicit conversions155
12.5 User-defined conversions155
12.5.1 General155
12.5.2 Permitted user-defined conversions156
12.5.3 Lifted conversion operators156
12.5.4 Evaluation of user-defined conversions156
12.5.5 User-defined implicit conversions157
12.5.6 User-defined explicit conversions158
12.6 Conversions involving nullable types160
12.6.1 Nullable Conversions160
12.6.2 Lifted conversions160
12.7 Anonymous function conversions160
12.7.1 General160
12.7.2 Evaluation of anonymous function conversions to delegate types162
12.7.3 Evaluation of anonymous function conversions to expression tree types162
12.7.4 Implementation example162
12.8 Method group conversions166
13. Expressions170
13.1 General170
13.2 Expression classifications170
13.2.1 General170
13.2.2 Values of expressions171
13.3 Static and Dynamic Binding171
13.3.1 General171
13.3.2 Binding-time172
13.3.3 Dynamic binding172
13.3.4 Types of subexpressions173
13.4 Operators173
13.4.1 General173
13.4.2 Operator precedence and associativity173
13.4.3 Operator overloading174
13.4.4 Unary operator overload resolution176
13.4.5 Binary operator overload resolution176
13.4.6 Candidate user-defined operators176
13.4.7 Numeric promotions177
13.4.7.1 General177
13.4.7.2 Unary numeric promotions177
13.4.7.3 Binary numeric promotions177
13.4.8 Lifted operators178
13.5 Member lookup179
13.5.1 General179
13.5.2 Base types180
13.6 Function members181
13.6.1 General181
13.6.2 Argument lists183
13.6.2.1 General183
13.6.2.2 Corresponding parameters184
13.6.2.3 Run-time evaluation of argument lists185
13.6.3 Type inference187
13.6.3.1 General187
13.6.3.2 The first phase188
13.6.3.3 The second phase188
13.6.3.4 Input types188
13.6.3.5 Output types188
13.6.3.6 Dependence188
13.6.3.7 Output type inferences189
13.6.3.8 Explicit parameter type inferences189
13.6.3.9 Exact inferences189
13.6.3.10 Lower-bound inferences189
13.6.3.11 Upper-bound inferences190
13.6.3.12 Fixing190
13.6.3.13 Inferred return type191
13.6.3.14 Type inference for conversion of method groups192
13.6.3.15 Finding the best common type of a set of expressions192
13.6.4 Overload resolution193
13.6.4.1 General193
13.6.4.2 Applicable function member193
13.6.4.3 Better function member194
13.6.4.4 Better conversion from expression196
13.6.4.5 Better conversion from type196
13.6.4.6 Better conversion target197
13.6.4.7 Overloading in generic classes197
13.6.5 Compile-time checking of dynamic overload resolution197
13.6.6 Function member invocation198
13.6.6.1 General198
13.6.6.2 Invocations on boxed instances199
13.7 Primary expressions200
13.7.1 General200
13.7.2 Literals200
13.7.3 Simple names201
13.7.3.1 General201
13.7.3.2 Invariant meaning in blocks202
13.7.4 Parenthesized expressions203
13.7.5 Member access203
13.7.5.1 General203
13.7.5.2 Identical simple names and type names205
13.7.6 Invocation expressions206
13.7.6.1 General206
13.7.6.2 Method invocations207
13.7.6.3 Extension method invocations208
13.7.6.4 Delegate invocations210
13.7.7 Element access211
13.7.7.1 General211
13.7.7.2 Array access211
13.7.7.3 Indexer access212
13.7.8 This access212
13.7.9 Base access213
13.7.10 Postfix increment and decrement operators214
13.7.11 The new operator215
13.7.11.1 General215
13.7.11.2 Object creation expressions216
13.7.11.3 Object initializers217
13.7.11.4 Collection initializers219
13.7.11.5 Array creation expressions221
13.7.11.6 Delegate creation expressions223
13.7.11.7 Anonymous object creation expressions226
13.7.12 The typeof operator227
13.7.13 The checked and unchecked operators230
13.7.14 Default value expressions232
13.7.15 Anonymous method expressions233
13.8 Unary operators240
13.8.1 General240
13.8.2 Unary plus operator240
13.8.3 Unary minus operator240
13.8.4 Logical negation operator241
13.8.5 Bitwise complement operator241
13.8.6 Prefix increment and decrement operators242
13.8.7 Cast expressions243
13.8.8 Await expressions244
13.8.8.1 General244
13.8.8.2 Awaitable expressions244
13.8.8.3 Classification of await expressions245
13.8.8.4 Run-time evaluation of await expressions245
13.9 Arithmetic operators245
13.9.1 General245
13.9.2 Multiplication operator246
13.9.3 Division operator247
13.9.4 Remainder operator248
13.9.5 Addition operator249
13.9.6 Subtraction operator251
13.10 Shift operators253
13.11 Relational and type-testing operators255
13.11.1 General255
13.11.2 Integer comparison operators255
13.11.3 Floating-point comparison operators256
13.11.4 Decimal comparison operators257
13.11.5 Boolean equality operators257
13.11.6 Enumeration comparison operators257
13.11.7 Reference type equality operators258
13.11.8 String equality operators260
13.11.9 Delegate equality operators261
13.11.10 Equality operators between nullable value types and the null literal262
13.11.11 The is operator262
13.11.12 The as operator263
13.12 Logical operators265
13.12.1 General265
13.12.2 Integer logical operators265
13.12.3 Enumeration logical operators266
13.12.4 Boolean logical operators266
13.12.5 Nullable Boolean & and | operators266
13.13 Conditional logical operators267
13.13.1 General267
13.13.2 Boolean conditional logical operators268
13.13.3 User-defined conditional logical operators268
13.14 The null coalescing operator269
13.15 Conditional operator269
13.16 Anonymous function expressions270
13.16.1 General270
13.16.2 Anonymous function signatures272
13.16.3 Anonymous function bodies273
13.16.4 Overload resolution273
13.16.5 Anonymous functions and dynamic binding274
13.16.6 Outer variables274
13.16.6.1 General274
13.16.6.2 Captured outer variables274
13.16.6.3 Instantiation of local variables275
13.16.7 Evaluation of anonymous function expressions277
13.17 Query expressions277
13.17.1 General277
13.17.2 Ambiguities in query expressions278
13.17.3 Query expression translation279
13.17.3.1 General279
13.17.3.2 Select and groupby clauses with continuations279
13.17.3.3 Explicit range variable types280
13.17.3.4 Degenerate query expressions280
13.17.3.5 From, let, where, join and orderby clauses281
13.17.3.6 Select clauses284
13.17.3.7 Groupby clauses284
13.17.3.8 Transparent identifiers285
13.17.4 The query expression pattern286
13.18 Assignment operators287
13.18.1 General287
13.18.2 Simple assignment288
13.18.3 Compound assignment290
13.18.4 Event assignment291
13.19 Expression291
13.20 Constant expressions291
13.21 Boolean expressions292
14. Statements295
14.1 General295
14.2 End points and reachability295
14.3 Blocks297
14.3.1 General297
14.3.2 Statement lists297
14.4 The empty statement298
14.5 Labeled statements298
14.6 Declaration statements299
14.6.1 General299
14.6.2 Local variable declarations299
14.6.3 Local constant declarations300
14.7 Expression statements301
14.8 Selection statements301
14.8.1 General301
14.8.2 The if statement302
14.8.3 The switch statement302
14.9 Iteration statements306
14.9.1 General306
14.9.2 The while statement306
14.9.3 The do statement306
14.9.4 The for statement307
14.9.5 The foreach statement308
14.10 Jump statements311
14.10.1 General311
14.10.2 The break statement312
14.10.3 The continue statement313
14.10.4 The goto statement313
14.10.5 The return statement314
14.10.6 The throw statement315
14.11 The try statement316
14.12 The checked and unchecked statements319
14.13 The lock statement319
14.14 The using statement320
14.15 The yield statement324
15. Namespaces327
15.1 General327
15.2 Compilation units327
15.3 Namespace declarations327
15.4 Extern alias directives329
15.5 Using directives329
15.5.1 General329
15.5.2 Using alias directives330
15.5.3 Using namespace directives334
15.6 Namespace member declarations336
15.7 Type declarations336
15.8 Qualified alias member337
15.8.1 General337
15.8.2 Uniqueness of aliases339
16. Classes341
16.1 General341
16.2 Class declarations341
16.2.1 General341
16.2.2 Class modifiers341
16.2.2.1 General341
16.2.2.2 Abstract classes342
16.2.2.3 Sealed classes342
16.2.2.4 Static classes343
16.2.3 Partial modifier344
16.2.4 Type parameters344
16.2.5 Class base specification344
16.2.5.1 General344
16.2.5.2 Base classes345
16.2.5.3 Interface implementations347
16.2.6 Type parameter constraints347
16.2.7 Class body352
16.3 Partial types353
16.3.1 General353
16.3.2 Attributes353
16.3.3 Modifiers354
16.3.4 Type parameters and constraints354
16.3.5 Base class355
16.3.6 Base interfaces355
16.3.7 Members355
16.3.8 Partial methods356
16.3.9 Name binding358
16.3.10 Field initialization359
16.4 Class members359
16.4.1 General359
16.4.2 The instance type360
16.4.3 Members of constructed types361
16.4.4 Inheritance362
16.4.5 The new modifier363
16.4.6 Access modifiers363
16.4.7 Constituent types364
16.4.8 Static and instance members364
16.4.9 Nested types365
16.4.9.1 General365
16.4.9.2 Fully qualified name365
16.4.9.3 Declared accessibility365
16.4.9.4 Hiding366
16.4.9.5 this access366
16.4.9.6 Access to private and protected members of the containing type367
16.4.9.7 Nested types in generic classes368
16.4.10 Reserved member names369
16.4.10.1 General369
16.4.10.2 Member names reserved for properties369
16.4.10.3 Member names reserved for events370
16.4.10.4 Member names reserved for indexers370
16.4.10.5 Member names reserved for finalizers370
16.5 Constants370
16.6 Fields372
16.6.1 General372
16.6.2 Static and instance fields373
16.6.3 Readonly fields373
16.6.3.1 General373
16.6.3.2 Using static readonly fields for constants374
16.6.3.3 Versioning of constants and static readonly fields374
16.6.4 Volatile fields375
16.6.5 Field initialization376
16.6.6 Variable initializers376
16.6.6.1 General376
16.6.6.2 Static field initialization377
16.6.6.3 Instance field initialization379
16.7 Methods379
16.7.1 General379
16.7.2 Method parameters381
16.7.2.1 General381
16.7.2.2 Value parameters383
16.7.2.3 Reference parameters383
16.7.2.4 Output parameters384
16.7.2.5 Parameter arrays385
16.7.3 Static and instance methods387
16.7.4 Virtual methods387
16.7.5 Override methods389
16.7.6 Sealed methods391
16.7.7 Abstract methods392
16.7.8 External methods393
16.7.9 Partial methods394
16.7.10 Extension methods394
16.7.11 Method body395
16.8 Properties396
16.8.1 General396
16.8.2 Static and instance properties397
16.8.3 Accessors397
16.8.4 Automatically implemented properties402
16.8.5 Accessibility403
16.8.6 Virtual, sealed, override, and abstract accessors404
16.9 Events406
16.9.1 General406
16.9.2 Field-like events408
16.9.3 Event accessors412
16.9.4 Static and instance events413
16.9.5 Virtual, sealed, override, and abstract accessors413
16.10 Indexers414
16.11 Operators417
16.11.1 General417
16.11.2 Unary operators418
16.11.3 Binary operators419
16.11.4 Conversion operators420
16.12 Instance constructors422
16.12.1 General422
16.12.2 Constructor initializers423
16.12.3 Instance variable initializers424
16.12.4 Constructor execution424
16.12.5 Default constructors426
16.13 Static constructors427
16.14 Finalizers429
16.15 Iterators431
16.15.1 General431
16.15.2 Enumerator interfaces431
16.15.3 Enumerable interfaces431
16.15.4 Yield type432
16.15.5 Enumerator objects432
16.15.5.1 General432
16.15.5.2 The MoveNext method432
16.15.5.3 The Current property433
16.15.5.4 The Dispose method434
16.15.6 Enumerable objects434
16.15.6.1 General434
16.15.6.2 The GetEnumerator method434
16.16 Async Functions441
16.16.1 General441
16.16.2 Evaluation of a task-returning async function441
16.16.3 Evaluation of a void-returning async function442
17. Structs443
17.1 General443
17.2 Struct declarations443
17.2.1 General443
17.2.2 Struct modifiers443
17.2.3 Partial modifier444
17.2.4 Struct interfaces444
17.2.5 Struct body444
17.3 Struct members444
17.4 Class and struct differences445
17.4.1 General445
17.4.2 Value semantics445
17.4.3 Inheritance446
17.4.4 Assignment446
17.4.5 Default values446
17.4.6 Boxing and unboxing447
17.4.7 Meaning of this448
17.4.8 Field initializers449
17.4.9 Constructors449
17.4.10 Static constructors450
17.4.11 Automatically implemented properties450
18. Arrays455
18.1 General455
18.2 Array types455
18.2.1 General455
18.2.2 The System.Array type456
18.2.3 Arrays and the generic IList interface456
18.3 Array creation457
18.4 Array element access457
18.5 Array members457
18.6 Array covariance457
18.7 Array initializers458
19. Interfaces461
19.1 General461
19.2 Interface declarations461
19.2.1 General461
19.2.2 Interface modifiers461
19.2.3 Partial modifier462
19.2.4 Variant type parameter lists462
19.2.4.1 General462
19.2.4.2 Variance safety462
19.2.4.3 Variance conversion463
19.2.5 Base interfaces463
19.3 Interface body464
19.4 Interface members464
19.4.1 General464
19.4.2 Interface methods465
19.4.3 Interface properties466
19.4.4 Interface events466
19.4.5 Interface indexers467
19.4.6 Interface member access467
19.5 Fully qualified interface member names469
19.6 Interface implementations469
19.6.1 General469
19.6.2 Explicit interface member implementations470
19.6.3 Uniqueness of implemented interfaces473
19.6.4 Implementation of generic methods474
19.6.5 Interface mapping474
19.6.6 Interface implementation inheritance477
19.6.7 Interface re-implementation479
19.6.8 Abstract classes and interfaces480
20. Enums481
20.1 General481
20.2 Enum declarations481
20.3 Enum modifiers481
20.4 Enum members482
20.5 The System.Enum type484
20.6 Enum values and operations484
21. Delegates485
21.1 General485
21.2 Delegate declarations485
21.3 Delegate compatibility488
21.4 Delegate instantiation488
21.5 Delegate invocation488
22. Exceptions491
22.1 General491
22.2 Causes of exceptions491
22.3 The System.Exception class491
22.4 How exceptions are handled492
22.5 Common exception classes492
23. Attributes495
23.1 General495
23.2 Attribute classes495
23.2.1 General495
23.2.2 Attribute usage495
23.2.3 Positional and named parameters497
23.2.4 Attribute parameter types497
23.3 Attribute specification498
23.4 Attribute instances505
23.4.1 General505
23.4.2 Compilation of an attribute505
23.4.3 Run-time retrieval of an attribute instance505
23.5 Reserved attributes506
23.5.1 General506
23.5.2 The AttributeUsage attribute507
23.5.3 The Conditional attribute507
23.5.3.1 General507
23.5.3.2 Conditional methods508
23.5.3.3 Conditional attribute classes510
23.5.4 The Obsolete attribute511
23.5.5 Caller-info attributes512
23.5.5.1 General512
23.5.5.2 The CallerLineNumber attribute513
23.5.5.3 The CallerFilePath attribute513
23.5.5.4 The CallerMemberName attribute514
23.6 Attributes for interoperation515
23.6.1 Interoperation with libraries515
23.6.2 Interoperation with other languages515
24. Unsafe code559
24.1 General559
24.2 Unsafe contexts559
24.3 Pointer types562
24.4 Fixed and moveable variables564
24.5 Pointer conversions565
24.5.1 General565
24.5.2 Pointer arrays566
24.6 Pointers in expressions567
24.6.1 General567
24.6.2 Pointer indirection567
24.6.3 Pointer member access568
24.6.4 Pointer element access569
24.6.5 The address-of operator569
24.6.6 Pointer increment and decrement570
24.6.7 Pointer arithmetic571
24.6.8 Pointer comparison571
24.6.9 The sizeof operator572
24.7 The fixed statement572
24.8 Fixed-size buffers576
24.8.1 General576
24.8.2 Fixed-size buffer declarations576
24.8.3 Fixed-size buffers in expressions577
24.8.4 Definite assignment checking578
24.9 Stack allocation578
24.10 Dynamic memory allocation579
Annex A. Grammar583
A.1 General583
A.2 Lexical grammar583
A.2.1 Comments584
A.2.2 Tokens584
A.2.3 Keywords586
A.2.4 Operators and punctuators588
A.2.5 Pre-processing directives588
A.3 Syntactic grammar591
A.3.1 Basic concepts591
A.3.2 Types591
A.3.3 Variables592
A.3.4 Expressions593
A.3.5 Statements599
A.3.6 Namespaces602
A.3.7 Classes603
A.3.8 Structs609
A.3.9 Arrays609
A.3.10 Interfaces610
A.3.11 Enums611
A.3.12 Delegates612
A.3.13 Attributes612
A.4 Grammar extensions for unsafe code613
Annex B. Portability issues617
B.1 General617
B.2 Undefined behavior617
B.3 Implementation-defined behavior617
B.4 Unspecified behavior618
B.5 Other Issues619
Annex C. Naming guidelines621
Annex D. Standard library623
Annex E. Documentation comments633
E.1 General633
E.2 Introduction633
E.3 Recommended tags634
E.3.1 General634
E.3.2 635
E.3.3 635
E.3.4 636
E.3.5 636
E.3.6 636
E.3.7 637
E.3.8 638
E.3.9 639
E.3.10 639
E.3.11 639
E.3.12 640
E.3.13 640
E.3.14 641
E.3.15 641
E.3.16 641
E.3.17 642
E.3.18 642
E.3.19 642
E.4 Processing the documentation file643
E.4.1 General643
E.4.2 ID string format643
E.4.3 ID string examples644
E.5 An example648
E.5.1 C# source code648
E.5.2 Resulting XML650
Annex F. Bibliography653
ECMA-334
Table of Contents
506
505
Foreword
This Standard replaces ECMA-334:2006. Changes from the previous edition include the following:
Addition of
#pragma warning preprocessing directive
default and hidden options on the #line preprocessing directive
dynamic type
implicit typing
fixed-size buffers in unsafe code
caller info attributes
async functions
query expressions
Removal of
unqualified names
concept of a null type
Integration of
nullable value types
generic types and functions
iterators
Introduction
This International Standard is based on a submission that was originally from Hewlett-Packard, Intel, and Microsoft, that described a language calledC#, which was developed within Microsoft. The principal inventors of this language were Anders Hejlsberg, Scott Wiltamuth, and Peter Golde. The first widely distributed implementation of C# was released by Microsoft in July 2000, as part of its .NET Framework initiative.
Ecma Technical Committee39 (TC39) Task Group2 (TG2) was formed in September 2000, to produce a standard forC#. Another Task Group, TG3, was also formed at that time to produce a standard for a library and execution environment called Common Language Infrastructure (CLI). (CLI is based on a subset of the .NET Framework.) Although Microsofts implementation of C# relies on CLI for library and run-time support, other implementations of C# need not, provided they support an alternate way of getting at the minimum CLI features required by this C#standard (see Annex D).
As the definition of C# evolved, the goals used in its design were as follows:
C# is intended to be a simple, modern, general-purpose, object-oriented programming language.
The language, and implementations thereof, should provide support for software engineering principles such as strong type checking, array bounds checking, detection of attempts to use uninitialized variables, and automatic garbage collection. Software robustness, durability, and programmer productivity are important.
The language is intended for use in developing software components suitable for deployment in distributed environments.
Source code portability is very important, as is programmer portability, especially for those programmers already familiar withC andC++.
Support for internationalization is very important.
C# is intended to be suitable for writing applications for both hosted and embedded systems, ranging from the very large that use sophisticated operating systems, down to the very small having dedicated functions.
Although C#applications are intended to be economical with regard to memory and processing power requirements, the language was not intended to compete directly on performance and size with C or assembly language.
A second edition was produced in 2006, which incorporated support for generics and iterators, among other things. Subsequently, committee Ecma TC39/TG2 was renamed to TC49/TG2.
The development of this version of the standard started in October 2014.
Introduction
Scope
This International Standard specifies the form and establishes the interpretation of programs written in the C#programming language. It specifies
The representation of C#programs;
The syntax and constraints of the C#language;
The semantic rules for interpreting C#programs;
The restrictions and limits imposed by a conforming implementation ofC#.
This International Standard does not specify
The mechanism by which C#programs are transformed for use by a data-processing system;
The mechanism by which C#applications are invoked for use by a data-processing system;
The mechanism by which input data are transformed for use by a C#application;
The mechanism by which output data are transformed after being produced by a C#application;
The size or complexity of a program and its data that will exceed the capacity of any specific data-processing system or the capacity of a particular processor;
All minimal requirements of a data-processing system that is capable of supporting a conforming implementation.
15 Namespaces
Conformance
Conformance is of interest to the following audiences:
Those designing, implementing, or maintaining C#implementations.
Governmental or commercial entities wishing to procure C#implementations.
Testing organizations wishing to provide a C#conformance test suite.
Programmers wishing to port code from one C#implementation to another.
Educators wishing to teach StandardC#.
Authors wanting to write about StandardC#.
As such, conformance is most important, and the bulk of this International Standard is aimed at specifying the characteristics that make C#implementations and C#programs conforming ones.
The text in this International Standard that specifies requirements is considered normative. All other text in this specification is informative; that is, for information purposes only. Unless stated otherwise, all text is normative. Normative text is further broken into required and conditional categories. Conditionally normative text specifies a feature and its requirements where the feature is optional. However, if that feature is provided, its syntax and semantics shall must be exactly as specified.
Undefined behavior is indicated in this International Standard only by the words undefined behavior.
A strictly conforming program shall use only those features of the language specified in this International Standard as being required. (This means that a strictly conforming program cannot use any conditionally normative feature.) It shall not produce output dependent on any unspecified, undefined, or implementation-defined behavior.
A conforming implementation of C# shall must accept any strictly conforming program.
A conforming implementation of C# shall must provide and support all the types, values, objects, properties, methods, and program syntax and semantics described in the normative (but not the conditionally normative) parts in this International Standard.
A conforming implementation of C# shall interpret characters in conformance with the Unicode Standard, Version4.0, and ISO/IEC 10646-1. Conforming implementations shall must accept Unicode source files encoded with the UTF-8 encoding form.
A conforming implementation of C# shall not successfully translate source containing a #error preprocessing directive unless it is part of a group skipped by conditional compilation.
A conforming implementation of C# shall produce at least one diagnostic message if the source program violates any rule of syntax, or any negative requirement (defined as a shall or shall not or error or warning requirement), unless that requirement is marked with the words no diagnostic is required.
A conforming implementation of C# is permitted to provide additional types, values, objects, properties, and methods beyond those described in this International Standard, provided they do not alter the behavior of any strictly conforming program. Conforming implementations are required to diagnose programs that use extensions that are ill formed according to this International Standard. Having done so, however, they can compile and execute such programs. (The ability to have extensions implies that a conforming implementation reserves no identifiers other than those explicitly reserved in this International Standard.)
A conforming implementation of C# shall be accompanied by a document that defines all implementation-defined characteristics, and all extensions.
A conforming implementation of C# shall support the class library documented inAnnex D. This library is included by reference in this International Standard.
A conforming program is one that is acceptable to a conforming implementation. (Such a program is permitted to contain extensions or conditionally normative features.)
Normative references
The following normative documents contain provisions, which, through reference in this text, constitute provisions of this International Standard. For dated references, subsequent amendments to, or revisions of, any of these publications do not apply. However, parties to agreements based on this International Standard are encouraged to investigate the possibility of applying the most recent editions of the normative documents indicated below. For undated references, the latest edition of the normative document referred to applies. Members of ISO and IEC maintain registers of currently valid International Standards.
ISO/IEC 23271:201205, Common Language Infrastructure (CLI), PartitionIV: Base Class Library (BCL), Extended Numerics Library, and Extended Array Library.
ISO 31.11:1992, Quantities and units Part 11: Mathematical signs and symbols for use in the physical sciences and technology.
ISO/IEC 2382.1:1993, Information technology Vocabulary Part 1: Fundamental terms.
ISO/IEC 10646 (all parts), Information technology Universal Multiple-Octet Coded Character Set (UCS).
IEC 60559:1989, Binary floating-point arithmetic for microprocessor systems (previously designated IEC 559:1989). (This standard is widely known by its U.S. national designation, ANSI/IEEE Standard 754-1985, IEEE Standard for Binary Floating-Point Arithmetic.)
The Unicode Consortium. The Unicode Standard, http://www.unicode.org/standard/standard.htmlVersion4.0, defined by: The Unicode Standard, Version4.0 (Boston, MA, Addison-Wesley, 2003. ISBN 0-321-18578-1).
Terms and definitions
For the purposes of this International Standard, the following definitions apply. Other terms are defined where they appear in italic type or on the left side of a syntax rule. Terms explicitly defined in this International Standard are not to be presumed to refer implicitly to similar terms defined elsewhere. Terms not defined in this International Standard are to be interpreted according to ISO/IEC 2382.1. Mathematical symbols not defined in this International Standard are to be interpreted according to ISO 31.11.
4.1applicationassembly with an entry pointrefers to an assembly that has an entry point ( REF _Ref501033702 \r \h 9.1). When an application is run, a new application domain is created. Several different instantiations of an application can exist on the same machine at the same time, and each has its own application domain.
4.2application domainentity that enables application isolation by acting as a container for application state. An application domain acts as a container and boundary for the types defined in the application and the class libraries it uses. Types loaded into one application domain are distinct from the same type loaded into another application domain, and instances of objects are not directly shared between application domains. For instance, each application domain has its own copy of static variables for these types, and a static constructor for a type is run at most once per application domain. Implementations are free to provide implementation-specific policy or mechanisms for the creation and destruction of application domains.
4.3argumentexpression in the comma-separated list bounded by the parentheses in a method or instance constructor call expression or bounded by the square brackets in an element access expression. It is also known as an actual argument.
4.4assemblyone or more files output by the compiler as a result of program compilation. An assembly is a configured set of loadable code modules and other resources that together implement a unit of functionality. An assembly can contain types, the executable code used to implement these types, and references to other assemblies. The physical representation of an assembly is not defined by this specification. Essentially, an assembly is the output of the compiler.
4.5behaviorexternal appearance or action
4.6behavior, implementation-definedunspecified behavior where each implementation documents how the choice is made
4.7behavior, undefinedbehavior, upon use of a non-portable or erroneous construct or of erroneous data, for which this International Standard imposes no requirements. [Possible handling of undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message)].
4.8behavior, unspecifiedbehavior where this International Standard provides two or more possibilities and imposes no further requirements on which is chosen in any instance.
4.9character (when used without a qualifier)a) In the context of a non-Unicode encoding the meaning of character in that encoding; or
b) In the context of a character literal or a value of type char a Unicode code point in the range U+0000 to U+FFFF (including surrogate code points), that is a UTF-16 code unit; or
c) Otherwise a Unicode code point
4.10class libraryassembly that can be used by other assemblies. Use of a class library does not cause the creation of a new application domain. Instead, a class library is loaded into the application domain that uses it. For instance, when an application uses a class library, that class library is loaded into the application domain for that application. If an application uses a class libraryA that itself uses a class libraryB, then both A and B are loaded into the application domain for the application.
4.11diagnostic messagemessage belonging to an implementation-defined subset of the implementations output messages
4.12error, compile-timeerror reported during program translation
4.13exceptionerror condition that is outside the ordinary expected behaviorexceptional condition reported during program execution
4.14implementationparticular set of software (running in a particular translation environment under particular control options) that performs translation of programs for, and supports execution of methods in, a particular execution environment
4.15namespacelogical organizational system that provides a way of presentinggrouping related program elements that are exposed to other programs
4.16parametervariable declared as part of a method, instance constructor, operator, or indexer definition, which acquires a value on entry to that function member. It is also known as a formal parameter.
4.17programone or more source files that are presented to the compiler. Essentially, a program is the input to the compiler.
4.18program, validC#program constructed according to the syntax rules and diagnosable semantic rules
4.19program instantiationexecution of an application
STYLEREF "Heading 1" \n \* MERGEFORMAT 4. SEQ TermsAndDefsLevel1 \n 20recommended practicespecification that is strongly recommended, as being aligned with the intent of the standard, but that might be impractical for some implementations
4.20source fileordered sequence of Unicode characters. Source files typically have a one-to-one correspondence with files in a file system, but this correspondence is not required.
4.21unsafe codecode that is permitted to perform such lower-level operations as declaring and operating on pointers, performing conversions between pointers and integral types, and taking the address of variables. Such operations provide functionality such as permitting interfacing with the underlying operating system, accessing a memory-mapped device, or implementing a time-critical algorithm.
4.22warning, compile-timeinformational message reported during program translation, which is intended to identify a potentially questionable usage of a program element
Notational conventions
Lexical and syntactic grammars for C# are interspersed throughout this specification. The lexical grammar defines how characters can be combined to form tokens ( REF _Ref462576650 \r \h \* MERGEFORMAT 9.4), the minimal lexical elements of the language. The syntactic grammar defines how tokens can be combined to make valid C#programs.
Grammar productions include both non-terminal and terminal symbols. In grammar productions, non-terminal symbols are shown in italic type, and terminal symbols are shown in a fixed-width font. Each non-terminal is defined by a set of productions. The first line of a set of productions is the name of the non-terminal, followed by one or two colons. One colon is used for a production in the syntactic grammar, two colons for a production in the lexical grammar. Each successive indented line contains the right-hand side for a production that has the non-terminal symbol as the left-hand side. For example:
class-modifier:newpublicprotectedinternalprivateabstractsealedstatic
defines the class-modifier non-terminal as having seven productions.
Alternatives are normally listed on separate lines, as shown above, though in cases where there are many alternatives, the phrase one of precedes a list of the options. This is simply shorthand for listing each of the alternatives on a separate line. For example:
decimal-digit: one of0 1 2 3 4 5 6 7 8 9
is equivalent to:
decimal-digit:0123456789
A subscripted suffix opt, as in identifieropt, is used as shorthand to indicate an optional symbol. The example:
for-statement:for ( for-initializeropt ; for-conditionopt ; for-iteratoropt ) embedded-statement
is equivalent to:
for-statement:for ( ; ; ) embedded-statementfor ( for-initializer ; ; ) embedded-statementfor ( ; for-condition ; ) embedded-statementfor ( ; ; for-iterator ) embedded-statementfor ( for-initializer ; for-condition ; ) embedded-statementfor ( ; for-condition ; for-iterator ) embedded-statementfor ( for-initializer ; ; for-iterator ) embedded-statementfor ( for-initializer ; for-condition ; for-iterator ) embedded-statement
All terminal characters are to be understood as the appropriate Unicode character from the range U+0020 to U+007F, as opposed to any similar-looking characters from other Unicode character ranges.
Acronyms and abbreviations
This clause is informative.
The following acronyms and abbreviations are used throughout this International Standard:
BCL Base Class Library, which provides types to represent the built-in data types of the CLI, simple file access, custom attributes, security attributes, string manipulation, formatting, streams, and collections.
CLI Common Language Infrastructure
CLS Common Language Specification
IEC the International Electrotechnical Commission
IEEE the Institute of Electrical and Electronics Engineers
ISO the International Organization for Standardization
The name C# is pronounced CSharp.
The name C# is written as the latin capital letterC (U+0043) followed by the number sign# (U+0023).
End of informative text.
General description
This text is informative.
This International Standard is intended to be used by implementers, academics, and application programmers. As such, it contains a considerable amount of explanatory material that, strictly speaking, is not necessary in a formal language specification.
This standard is divided into the following subdivisions:
Front matter (clauses16);
Language overview (clause7);
The language syntax, constraints, and semantics (clauses824);
Annexes
Examples are provided to illustrate possible forms of the constructions described. References are used to refer to related clauses. Notes are provided to give advice or guidance to implementers or programmers. Annexes provide additional information and summarize the information contained in this International Standard.
Clauses14, part of Clause6, Clauses 823, the beginning of Clause24, and most of Annex D form a normative part of this standard. With the exception of the beginning, all of Clause24 is conditionally normative. The Foreword, Introduction, Clause5, part of Clause6, Clause7, Annexes A, B, C, part of AnnexesD, E, andF, notes, and examples are informative.
End of informative text.
Informative text is indicated in the following ways:
1. Whole or partial clauses or annexes delimited by This clause/text is informativeand End of informative text.
2. [Example: The following example code fragment, possibly with some narrative end example]
3. [Note: narrative end note]
All text not marked as being informative is normative.
Language overview
This clause is informative.
General
C# (pronounced See Sharp) is a simple, modern, object-oriented, and type-safe programming language. C# has its roots in the Cfamily of languages and will be immediately familiar toC, C++, and Java programmers.
C# is an object-oriented language, but C#further includes support for component-oriented programming. Contemporary software design increasingly relies on software components in the form of self-contained and self-describing packages of functionality. Key to such components is that they present a programming model with properties, methods, and events; they have attributes that provide declarative information about the component; and they incorporate their own documentation. C# provides language constructs to support directly these concepts, makingC# a very natural language in which to create and use software components.
Several C#features aid in the construction of robust and durable applications: Garbage collection automatically reclaims memory occupied by unreachable unused objects; exception handling provides a structured and extensible approach to error detection and recovery; and the type-safe design of the language makes it impossible to read from uninitialized variables, to index arrays beyond their bounds, or to perform unchecked type casts.
C# has a unified type system. All C#types, including primitive types such as int and double, inherit from a single root object type. Thus, all types share a set of common operations, and values of any type can be stored, transported, and operated upon in a consistent manner. Furthermore, C#supports both user-defined reference types and value types, allowing dynamic allocation of objects as well as in-line storage of lightweight structures.
To ensure that C#programs and libraries can evolve over time in a compatible manner, much emphasis has been placed on versioning in C#sdesign. Many programming languages pay little attention to this issue, and, as a result, programs written in those languages break more often than necessary when newer versions of dependent libraries are introduced. Aspects of C#sdesign that were directly influenced by versioning considerations include the separate virtual and override modifiers, the rules for method overload resolution, and support for explicit interface member declarations.
The rest of this clause describes the essential features of the C#language. Although later clauses describe rules and exceptions in a detail-oriented and sometimes mathematical manner, this clause strives for clarity and brevity at the expense of completeness. The intent is to provide the reader with an introduction to the language that will facilitate the writing of early programs and the reading of later clauses.
Hello world
The Hello, World program is traditionally used to introduce a programming language. Here it is inC#:
using System;
class Hello{static void Main() {Console.WriteLine("Hello, World");}}
C#source files typically have the file extension .cs. Assuming that the Hello, World program is stored in the file hello.cs, the program might be compiled using the command line
csc hello.cs
which produces an executable assembly named hello.exe. The output produced by this application when it is run is
Hello, World
The Hello, World program starts with a using directive that references the System namespace. Namespaces provide a hierarchical means of organizing C#programs and libraries. Namespaces contain types and other namespacesfor example, the System namespace contains a number of types, such as the Console class referenced in the program, and a number of other namespaces, such as IO and Collections. A using directive that references a given namespace enables unqualified use of the types that are members of that namespace. Because of the using directive, the program can use Console.WriteLine as shorthand for System.Console.WriteLine.
The Hello class declared by the Hello, World program has a single member, the method named Main. The Main method is declared with the static modifier. While instance methods can reference a particular enclosing object instance using the keyword this, static methods operate without reference to a particular object. By convention, a static method named Main serves as the entry point of a program.
The output of the program is produced by the WriteLine method of the Console class in the System namespace. This class is provided by the standard class libraries, which, by default, are automatically referenced by the compiler.
Program structure
The key organizational concepts in C# are programs, namespaces, types, members, and assemblies. C#programs consist of one or more source files. Programs declare types, which contain members and can be organized into namespaces. Classes and interfaces are examples of types. Fields, methods, properties, and events are examples of members. When C#programs are compiled, they are physically packaged into assemblies. Assemblies typically have the file extension .exe or .dll, depending on whether they implement applications or libraries, respectively.
The example
using System;
namespace Acme.Collections{public class Stack{Entry top;
public void Push(object data) {top = new Entry(top, data);}
public object Pop() {if (top == null) throw new InvalidOperationException();object result = top.data;top = top.next;return result;}
class Entry{public Entry next;public object data;
public Entry(Entry next, object data) {this.next = next;this.data = data;}}}}
declares a class named Stack in a namespace called Acme.Collections. The fully qualified name of this class is Acme.Collections.Stack. The class contains several members: a field named top, two methods named Push and Pop, and a nested class named Entry. The Entry class further contains three members: a field named next, a field named data, and a constructor. Assuming that the source code of the example is stored in the file acme.cs, the command line
csc /t:library acme.cs
compiles the example as a library (code without a Main entry point) and produces an assembly named acme.dll.
Assemblies contain executable code in the form of Intermediate Language (IL) instructions, and symbolic information in the form of metadata. Before it is executed, the IL code in an assembly is automatically converted to processor-specific code by the Just-In-Time (JIT) compiler of .NET Common Language Runtime.
Because an assembly is a self-describing unit of functionality containing both code and metadata, there is no need for #include directives and header files inC#. The public types and members contained in a particular assembly are made available in a C#program simply by referencing that assembly when compiling the program. For example, this program uses the Acme.Collections.Stack class from the acme.dll assembly:
using System;using Acme.Collections;
class Test{static void Main() {Stack s = new Stack();s.Push(1);s.Push(10);s.Push(100);Console.WriteLine(s.Pop());Console.WriteLine(s.Pop());Console.WriteLine(s.Pop());}}
If the program is stored in the file test.cs, when test.cs is compiled, the acme.dll assembly can be referenced using the compilers /roption:
csc /r:acme.dll test.cs
This creates an executable assembly named test.exe, which, when run, produces the output:
100101
C#permits the source text of a program to be stored in several source files. When a multi-file C#program is compiled, all of the source files are processed together, and the source files can freely reference each otherconceptually, it is as if all the source files were concatenated into one large file before being processed. Forward declarations are never needed inC# because, with very few exceptions, declaration order is insignificant. C#does not limit a source file to declaring only one public type nor does it require the name of the source file to match a type declared in the source file.
Types and variables
There are two kinds of types inC#: value types and reference types. Variables of value types directly contain their data whereas variables of reference types store references to their data, the latter being known as objects. With reference types, it is possible for two variables to reference the same object and thus possible for operations on one variable to affect the object referenced by the other variable. With value types, the variables each have their own copy of the data, and it is not possible for operations on one to affect the other (except in the case of ref and out parameter variables).
C#s value types are further divided into simple types, enum types, struct types, and nullable value types, and C#s reference types are further divided into class types, interface types, array types, and delegate types.
The following table provides an overview of C#stype system.
Category
Description
Valuetypes
Simple types
Signed integral: sbyte, short, int, long
Unsigned integral: byte, ushort, uint, ulong
Unicode characters: char
IEEE floating point: float, double
High-precision decimal: decimal
Boolean: bool
Enum types
User-defined types of the form enum E {}
Struct types
User-defined types of the form struct S {}
Nullable value types
Extensions of all other value types with a null value
Referencetypes
Class types
Ultimate base class of all other types: object
Unicode strings: string
User-defined types of the form class C {}
Interface types
User-defined types of the form interface I {}
Array types
Single- and multi-dimensional, for example, int[] and int[,]
Delegate types
User-defined types of the form e.g. delegate int D()
The eight integral types provide support for 8-bit, 16-bit, 32-bit, and 64-bit values in signed or unsigned form.
The two floating-point types, float and double, are represented using the 32-bit single-precision and 64-bit double-precision IEC-60559 formats, respectively.
The decimal type is a 128-bit data type suitable for financial and monetary calculations.
C#s bool type is used to represent Boolean valuesvalues that are either true or false.
Character and string processing in C# uses Unicode encoding. The char type represents a UTF-16 code unit, and the string type represents a sequence of UTF-16 code units.
The following table summarizes C#snumeric types.
Category
Bits
Type
Range/Precision
Signed integral
8
sbyte
128...127
16
short
32,768...32,767
32
int
2,147,483,648...2,147,483,647
64
long
9,223,372,036,854,775,808...9,223,372,036,854,775,807
Unsigned integral
8
byte
0...255
16
ushort
0...65,535
32
uint
0...4,294,967,295
64
ulong
0...18,446,744,073,709,551,615
Floating point
32
float
1.51045 to 3.41038, 7-digit precision
64
double
5.010324 to 1.710308, 15-digit precision
Decimal
128
decimal
1.01028 to 7.91028, 28-digit precision
C#programs use type declarations to create new types. A type declaration specifies the name and the members of the new type. Five of C#scategories of types are user-definable: class types, struct types, interface types, enum types, and delegate types.
A class type defines a data structure that contains data members (fields) and function members (methods, properties, and others). Class types support single inheritance and polymorphism, mechanisms whereby derived classes can extend and specialize base classes.
A struct type is similar to a class type in that it represents a structure with data members and function members. However, unlike classes, structs are value types and do not require heap allocation. Struct types do not support user-specified inheritance, and all struct types implicitly inherit from type object.
An interface type defines a contract as a named set of public function members. A class or struct that implements an interface must provide implementations of the interfaces function members. An interface may inherit from multiple base interfaces, and a class or struct may implement multiple interfaces.
A delegate type represents references to methods with a particular parameter list and return type. Delegates make it possible to treat methods as entities that can be assigned to variables and passed as parameters. Delegates are similar to the concept of function pointers found in some other languages, but unlike function pointers, delegates are object-oriented and type-safe.
Class, struct, interface and delegate types all support generics, whereby they can be parameterized with other types.
An enum type is a distinct type with named constants. Every enum type has an underlying type, which must be one of the eight integral types. The set of values of an enum type is the same as the set of values of the underlying type.
C# supports single- and multi-dimensional arrays of any type. Unlike the types listed above, array types do not have to be declared before they can be used. Instead, array types are constructed by following a type name with square brackets. For example, int[] is a single-dimensional array of int, int[,] is a two-dimensional array of int, and int[][] is a single-dimensional array of single-dimensional arrays of int.
Nullable value types also do not have to be declared before they can be used. For each non-nullable value typeT there is a corresponding nullable value typeT?, which can hold an additional value, null. For instance, int? is a type that can hold any 32-bit integer or the value null.
C#stype system is unified such that a value of any type can be treated as an object. Every type in C# directly or indirectly derives from the object class type, and object is the ultimate base class of all types. Values of reference types are treated as objects simply by viewing the values as type object. Values of value types are treated as objects by performing boxing and unboxing operations. In the following example, an int value is converted to object and back again to int.
using System;
class Test{static void Main() {int i = 123;object o = i;// Boxingint j = (int)o;// Unboxing}}
When a value of a value type is converted to type object, an object instance, also called a box, is allocated to hold the value, and the value is copied into that box. Conversely, when an object reference is cast to a value type, a check is made that the referenced object is a box of the correct value type, and, if the check succeeds, the value in the box is copied out.
C#sunified type system effectively means that value types can become objects on demand. Because of the unification, general-purpose libraries that use type object can be used with both reference types and value types.
There are several kinds of variables inC#, including fields, array elements, local variables, and parameters. Variables represent storage locations, and every variable has a type that determines what values can be stored in the variable, as shown by the following table.
Type of Variable
Possible Contents
Non-nullable value type
A value of that exact type
Nullable value type
A null value or a value of that exact type
object
A null reference, a reference to an object of any reference type, or a reference to a boxed value of any value type
Class type
A null reference, a reference to an instance of that class type, or a reference to an instance of a class derived from that class type
Interface type
A null reference, a reference to an instance of a class type that implements that interface type, or a reference to a boxed value of a value type that implements that interface type
Array type
A null reference, a reference to an instance of that array type, or a reference to an instance of a compatible array type
Delegate type
A null reference or a reference to an instance of a compatible that delegate type
Expressions
Expressions are constructed from operands and operators. The operators of an expression indicate which operations to apply to the operands. Examples of operators include+, -, *, /, and new. Examples of operands include literals, fields, local variables, and expressions.
When an expression contains multiple operators, the precedence of the operators controls the order in which the individual operators are evaluated. For example, the expression x+y*z is evaluated as x+(y*z) because the *operator has higher precedence than the +operator.
When an operand occurs between two operators with the same precedence, the associativity of the operators controls the order in which the operations are performed:
Except for the assignment operators, all binary operators are left-associative, meaning that operations are performed from left to right. For example, x+y+z is evaluated as(x+y)+z.
The assignment operators and the conditional operator (?:) are right-associative, meaning that operations are performed from right to left. For example, x=y=z is evaluated as x=(y=z).
Precedence and associativity can be controlled using parentheses. For example, x+y*z first multipliesy byz and then adds the result tox, but (x+y)*z first addsx andy and then multiplies the result byz.
Most operators can be overloaded. Operator overloading permits user-defined operator implementations to be specified for operations where one or both of the operands are of a user-defined class or struct type.
The following table summarizes C#s operators, listing the operator categories in order of precedence from highest to lowest. Operators in the same category have equal precedence.
Category
Expression
Description
Primary (13.7)
x.m
Member access
x()
Method and delegate invocation
x[]
Array and indexer access
x++
Post-increment
x--
Post-decrement
new T()
Object and delegate creation
new T(){}
Object creation with initializer
new {}
Anonymous object initializer
new T[]
Array creation
typeof(T)
Obtain System.Type object forT
checked(x)
Evaluate expression in checked context
unchecked(x)
Evaluate expression in unchecked context
default(T)
Obtain default value of typeT
delegate {...}
Anonymous function (anonymous method)
Unary (13.8)
+x
Identity
-x
Negation
!x
Logical negation
~x
Bitwise negation
++x
Pre-increment
--x
Pre-decrement
(T)x
Explicitly convert x to type T
await x
Asynchronously wait for x to complete
Multiplicative (13.9)
x * y
Multiplication
x / y
Division
x % y
Remainder
Additive (13.9)
x + y
Addition, string concatenation, delegate combination
x y
Subtraction, delegate removal
Shift (13.10)
x > y
Shift right
Relational and type testing (13.11)
x < y
Less than
x > y
Greater than
x = y
Greater than or equal
x is T
Return true ifx is aT, false otherwise
x as T
Returnx typed asT, or null ifx is not aT
Equality (13.11)
x == y
Equal
x != y
Not equal
Logical AND (13.12)
x & y
Integer bitwise AND, boolean logical AND
Logical XOR (13.12)
x ^ y
Integer bitwise XOR, boolean logical XOR
Logical OR (13.12)
x | y
Integer bitwise OR, boolean logical OR
Conditional AND (13.13)
x && y
Evaluatesy only ifx is true
Conditional OR (13.13)
x || y
Evaluatesy only ifx is false
Null coalescing (13.14)
X ?? y
Evaluates toy ifx is null, tox otherwise
Conditional (13.15)
x ? y : z
Evaluatesy ifx is true, z ifx is false
Assignment (13.18) or anonymous function (13.16)
x = y
Assignment
x op= y
Compound assignment; supported operators are
*= /= %= += -= = &= ^= |=
(T x) => y
Anonymous function (lambda expression)
Statements
The actions of a program are expressed using statements. C#supports several different kinds of statements, a number of which are defined in terms of embedded statements.
A block permits multiple statements to be written in contexts where a single statement is allowed. A block consists of a list of statements written between the delimiters{ and}.
Declaration statements are used to declare local variables and constants.
Expression statements are used to evaluate expressions. Expressions that can be used as statements include method invocations, object allocations using the new operator, assignments using = and the compound assignment operators, increment and decrement operations using the ++ and --operators and await expressions.
Selection statements are used to select one of a number of possible statements for execution based on the value of some expression. In this group are the if and switch statements.
Iteration statements are used to execute repeatedly an embedded statement. In this group are the while, do, for, and foreach statements.
Jump statements are used to transfer control. In this group are the break, continue, goto, throw, return, and yield statements.
The try...catch statement is used to catch exceptions that occur during execution of a block, and the try...finally statement is used to specify finalization code that is always executed, whether an exception occurred or not.
The checked and unchecked statements are used to control the overflow-checking context for integral-type arithmetic operations and conversions.
The lock statement is used to obtain the mutual-exclusion lock for a given object, execute a statement, and then release the lock.
The using statement is used to obtain a resource, execute a statement, and then dispose of that resource.
The following table lists the kinds of statements that can be used, and provides an example for each.
Statement
Example
Local variable declaration
static void Main() {int a; int b = 2, c = 3; a = 1;Console.WriteLine(a + b + c);}
Local constant declaration
static void Main() {const float pi = 3.1415927f;const int r = 25;Console.WriteLine(pi * r * r);}
Expression statement
static void Main() {int i;i = 123;// Expression statementConsole.WriteLine(i);// Expression statementi++;// Expression statementConsole.WriteLine(i);// Expression statement}
if statement
static void Main(string[] args) {if (args.Length == 0) {Console.WriteLine("No arguments");}else {Console.WriteLine("One or more arguments");}}
switch statement
static void Main(string[] args) {int n = args.Length;switch (n) {case 0:Console.WriteLine("No arguments");break;case 1:Console.WriteLine("One argument");break;default:Console.WriteLine("{0} arguments", n);break;}}}
while statement
static void Main(string[] args) {int i = 0;while (i < args.Length) {Console.WriteLine(args[i]);i++;}}
do statement
static void Main() {string s;do {s = Console.ReadLine();if (s != null) Console.WriteLine(s);} while (s != null);}
for statement
static void Main(string[] args) {for (int i = 0; i < args.Length; i++) {Console.WriteLine(args[i]);}}
foreach statement
static void Main(string[] args) {foreach (string s in args) {Console.WriteLine(s);}}
break statement
static void Main() {while (true) {string s = Console.ReadLine();if (s == null) break;Console.WriteLine(s);}}
continue statement
static void Main(string[] args) {for (int i = 0; i < args.Length; i++) {if (args[i].StartsWith("/")) continue;Console.WriteLine(args[i]);}}
goto statement
static void Main(string[] args) {int i = 0;goto check;loop:Console.WriteLine(args[i++]);check:if (i < args.Length) goto loop;}
return statement
static int Add(int a, int b) { return a + b;}
static void Main() { Console.WriteLine(Add(1, 2)); return;}
yield statement
static IEnumerable Range(int from, int to) {for (int i = from; i < to; i++) {yield return i;}yield break;}
static void Main() {foreach (int x in Range(-10,10)) {Console.WriteLine(x);}}
throw statements and try statements
static double Divide(double x, double y) {if (y == 0) throw new DivideByZeroException();return x / y;}
static void Main(string[] args) {try {if (args.Length != 2) {throw new Exception("Two numbers required");}double x = double.Parse(args[0]);double y = double.Parse(args[1]);Console.WriteLine(Divide(x, y));}catch (Exception e) {Console.WriteLine(e.Message);}finally {Console.WriteLine(Good bye!);}}
checked and unchecked statements
static void Main() { int x = int.MaxValue; checked { Console.WriteLine(x + 1); // Exception } unchecked { Console.WriteLine(x + 1); // Overflow }}
lock statement
class Account{decimal balance;
private readonly object sync = new object();
public void Withdraw(decimal amount) {lock (thissync) {if (amount > balance) {throw new Exception("Insufficient funds");}balance -= amount;}}}
using statement
static void Main() {using (TextWriter w = File.CreateText("test.txt")) {w.WriteLine("Line one");w.WriteLine("Line two");w.WriteLine("Line three");}}
Classes and objectsGeneral
Classes are the most fundamental of C#stypes. A class is a data structure that combines state (fields) and actions (methods and other function members) in a single unit. A class provides a definition for dynamically created instances of the class, also known as objects. Classes support inheritance and polymorphism, mechanisms whereby derived classes can extend and specialize base classes.
New classes are created using class declarations. A class declaration starts with a header that specifies the attributes and modifiers of the class, the name of the class, the base class (if given), and the interfaces implemented by the class. The header is followed by the class body, which consists of a list of member declarations written between the delimiters{ and}.
The following is a declaration of a simple class named Point:
public class Point{public int x, y;
public Point(int x, int y) {this.x = x;this.y = y;}}
Instances of classes are created using the new operator, which allocates memory for a new instance, invokes a constructor to initialize the instance, and returns a reference to the instance. The following statements create two Point objects and store references to those objects in two variables:
Point p1 = new Point(0, 0);Point p2 = new Point(10, 20);
The memory occupied by an object is automatically reclaimed when the object is no longer reachablein use. It is neither necessary nor possible to explicitly deallocate objects inC#.
Members
The members of a class are either static members or instance members. Static members belong to classes, and instance members belong to objects (instances of classes).
The following table provides an overview of the kinds of members a class can contain.
Member
Description
Constants
Constant values associated with the class
Fields
Variables of the class
Methods
Computations and actions that can be performed by the class
Properties
Actions associated with reading and writing named properties of the class
Indexers
Actions associated with indexing instances of the class like an array
Events
Notifications that can be generated by the class
Operators
Conversions and expression operators supported by the class
Constructors
Actions required to initialize instances of the class or the class itself
Finalizers
Actions to perform before instances of the class are permanently discarded
Types
Nested types declared by the class
Accessibility
Each member of a class has an associated accessibility, which controls the regions of program text that are able to access the member. There are five possible forms of accessibility. These are summarized in the following table.
Accessibility
Meaning
public
Access not limited
protected
Access limited to this class or classes derived from this class
internal
Access limited to this program
protected internal
Access limited to this program or classes derived from this class
private
Access limited to this class
Type parameters
A class definition may specify a set of type parameters by following the class name with angle brackets enclosing a list of type parameter names. The type parameters can then be used in the body of the class declarations to define the members of the class. In the following example, the type parameters of Pair are TFirst and TSecond:
public class Pair{public TFirst First;public TSecond Second;}
A class type that is declared to take type parameters is called a generic class type. Struct, interface and delegate types can also be generic.
When the generic class is used, type arguments must be provided for each of the type parameters:
Pair pair = new Pair { First = 1, Second = two };int i = pair.First; // TFirst is intstring s = pair.Second; // TSecond is string
A generic type with type arguments provided, like Pair above, is called a constructed type.
Base classes
A class declaration may specify a base class by following the class name and type parameters with a colon and the name of the base class. Omitting a base class specification is the same as deriving from type object. In the following example, the base class of Point3D is Point, and the base class of Point is object:
public class Point{public int x, y;
public Point(int x, int y) {this.x = x;this.y = y;}}
public class Point3D: Point{public int z;
public Point3D(int x, int y, int z): base(x, y) {this.z = z;}}
A class inherits the members of its base class. Inheritance means that a class implicitly contains all members of its base class, except for the instance and static constructors, and the finalizers of the base class. A derived class can add new members to those it inherits, but it cannot remove the definition of an inherited member. In the previous example, Point3D inherits the x and y fields from Point, and every Point3D instance contains three fields, x, y, and z.
An implicit conversion exists from a class type to any of its base class types. Therefore, a variable of a class type can reference an instance of that class or an instance of any derived class. For example, given the previous class declarations, a variable of type Point can reference either a Point or a Point3D:
Point a = new Point(10, 20);Point b = new Point3D(10, 20, 30);
Fields
A field is a variable that is associated with a class or with an instance of a class.
A field declared with the static modifier defines a static field. A static field identifies exactly one storage location. No matter how many instances of a class are created, there is only ever one copy of a static field.
A field declared without the static modifier defines an instance field. Every instance of a class contains a separate copy of all the instance fields of that class.
In the following example, each instance of the Color class has a separate copy of ther, g, andb instance fields, but there is only one copy of the Black, White, Red, Green, and Blue static fields:
public class Color{public static readonly Color Black = new Color(0, 0, 0);public static readonly Color White = new Color(255, 255, 255);public static readonly Color Red = new Color(255, 0, 0);public static readonly Color Green = new Color(0, 255, 0);public static readonly Color Blue = new Color(0, 0, 255);
private byte r, g, b;
public Color(byte r, byte g, byte b) {this.r = r;this.g = g;this.b = b;}}
As shown in the previous example, read-only fields may be declared with a readonly modifier. Assignment to a readonly field can only occur as part of the fields declaration or in a constructor in the same class.
MethodsGeneral
A method is a member that implements a computation or action that can be performed by an object or class. Static methods are accessed through the class. Instance methods are accessed through instances of the class.
Methods have a (possibly empty) list of parameters, which represent values or variable references passed to the method, and a return type, which specifies the type of the value computed and returned by the method. A methods return type is void if it does not return a value.
Like types, methods may also have a set of type parameters, for which type arguments must be specified when the method is called. Unlike types, the type arguments can often be inferred from the arguments of a method call and need not be explicitly given.
The signature of a method must be unique in the class in which the method is declared. The signature of a method consists of the name of the method, the number of type parameters and the number, modifiers, and types of its parameters. The signature of a method does not include the return type.
Parameters
Parameters are used to pass values or variable references to methods. The parameters of a method get their actual values from the arguments that are specified when the method is invoked. There are four kinds of parameters: value parameters, reference parameters, output parameters, and parameter arrays.
A value parameter is used for input parameter passing. A value parameter corresponds to a local variable that gets its initial value from the argument that was passed for the parameter. Modifications to a value parameter do not affect the argument that was passed for the parameter.
Value parameters can be optional, by specifying a default value so that corresponding arguments can be omitted.
A reference parameter is used for both input and output parameter passing. The argument passed for a reference parameter must be a variable, and during execution of the method, the reference parameter represents the same storage location as the argument variable. A reference parameter is declared with the ref modifier. The following example shows the use of ref parameters.
using System;
class Test{static void Swap(ref int x, ref int y) {int temp = x;x = y;y = temp;}
static void Main() {int i = 1, j = 2;Swap(ref i, ref j);Console.WriteLine("{0} {1}", i, j);// Outputs "2 1"}}
An output parameter is used for output parameter passing. An output parameter is similar to a reference parameter except that the initial value of the caller-provided argument is unimportant. An output parameter is declared with the out modifier. The following example shows the use of out parameters.
using System;
class Test{static void Divide(int x, int y, out int result, out int remainder) {result = x / y;remainder = x % y;}
static void Main() {int res, rem;Divide(10, 3, out res, out rem);Console.WriteLine("{0} {1}", res, rem);// Outputs "3 1"}}
A parameter array permits a variable number of arguments to be passed to a method. A parameter array is declared with the params modifier. Only the last parameter of a method can be a parameter array, and the type of a parameter array must be a single-dimensional array type. The Write and WriteLine methods of the System.Console class are good examples of parameter array usage. They are declared as follows.
public class Console{public static void Write(string fmt, params object[] args) {}public static void WriteLine(string fmt, params object[] args) {}}
Within a method that uses a parameter array, the parameter array behaves exactly like a regular parameter of an array type. However, in an invocation of a method with a parameter array, it is possible to pass either a single argument of the parameter array type or any number of arguments of the element type of the parameter array. In the latter case, an array instance is automatically created and initialized with the given arguments. This example
Console.WriteLine("x={0} y={1} z={2}", x, y, z);
is equivalent to writing the following.
string s = "x={0} y={1} z={2}";object[] args = new object[3];args[0] = x;args[1] = y;args[2] = z;Console.WriteLine(s, args);
Method body and local variables
A methods body specifies the statements to execute when the method is invoked.
A method body can declare variables that are specific to the invocation of the method. Such variables are called local variables. A local variable declaration specifies a type name, a variable name, and possibly an initial value. The following example declares a local variablei with an initial value of zero and a local variablej with no initial value.
using System;
class Squares{static void Main() {int i = 0;int j;while (i < 10) {j = i * i;Console.WriteLine("{0} x {0} = {1}", i, j);i = i + 1;}}}
C# requires a local variable to be definitely assigned before its value can be obtained. For example, if the declaration of the previousi did not include an initial value, the compiler would report an error for the subsequent usages ofi becausei would not be definitely assigned at those points in the program.
A method can use return statements to return control to its caller. In a method returning void, return statements cannot specify an expression. In a method returning non-void, return statements must include an expression that computes the return value.
Static and instance methods
A method declared with a static modifier is a static method. A static method does not operate on a specific instance and can only directly access static members.
A method declared without a static modifier is an instance method. An instance method operates on a specific instance and can access both static and instance members. The instance on which an instance method was invoked can be explicitly accessed as this. It is an error to refer to this in a static method.
The following Entity class has both static and instance members.
class Entity{static int nextSerialNo;
int serialNo;
public Entity() {serialNo = nextSerialNo++;}
public int GetSerialNo() {return serialNo;}
public static int GetNextSerialNo() {return nextSerialNo;}
public static void SetNextSerialNo(int value) {nextSerialNo = value;}}
Each Entity instance contains a serial number (and presumably some other information that is not shown here). The Entity constructor (which is like an instance method) initializes the new instance with the next available serial number. Because the constructor is an instance member, it is permitted to access both the serialNo instance field and the nextSerialNo static field.
The GetNextSerialNo and SetNextSerialNo static methods can access the nextSerialNo static field, but it would be an error for them to directly access the serialNo instance field.
The following example shows the use of the Entity class.
using System;
class Test{static void Main() {Entity.SetNextSerialNo(1000);
Entity e1 = new Entity();Entity e2 = new Entity();
Console.WriteLine(e1.GetSerialNo());// Outputs "1000"Console.WriteLine(e2.GetSerialNo());// Outputs "1001"Console.WriteLine(Entity.GetNextSerialNo());// Outputs "1002"}}
Note that the SetNextSerialNo and GetNextSerialNo static methods are invoked on the class whereas the GetSerialNo instance method is invoked on instances of the class.
Virtual, override, and abstract methods
When an instance method declaration includes a virtual modifier, the method is said to be a virtual method. When no virtual modifier is present, the method is said to be a non-virtual method.
When a virtual method is invoked, the run-time type of the instance for which that invocation takes place determines the actual method implementation to invoke. In a nonvirtual method invocation, the compile-time type of the instance is the determining factor.
A virtual method can be overridden in a derived class. When an instance metho