c# language specification - ecma international shar… · web viewin fact the second string...
TRANSCRIPT
C# Language Specification
C#
Language Specification
Working Draft WD3.14
November 16 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
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 Members84
9.4.1 General84
9.4.2 Namespace members84
9.4.3 Struct members84
9.4.4 Enumeration members85
9.4.5 Class members85
9.4.6 Interface members85
9.4.7 Array members85
9.4.8 Delegate members85
9.5 Member access85
9.5.1 General85
9.5.2 Declared accessibility86
9.5.3 Accessibility domains86
9.5.4 Protected access for instance members89
9.5.5 Accessibility constraints90
9.6 Signatures and overloading91
9.7 Scopes92
9.7.1 General92
9.7.2 Name hiding95
9.7.2.1 General95
9.7.2.2 Hiding through nesting95
9.7.2.3 Hiding through inheritance96
9.8 Namespace and type names97
9.8.1 General97
9.8.2 Fully qualified names99
9.9 Automatic memory management100
9.10 Execution order103
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 constant expressions135
11.4.4.22 General rules for simple expressions136
11.4.4.23 General rules for expressions with embedded expressions136
11.4.4.24 Invocation expressions and object creation expressions136
11.4.4.25 Simple assignment 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 ?: expressions140
11.4.4.31 Anonymous functions140
11.5 Variable references142
11.6 Atomicity of variable references142
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 types163
12.7.4 Implementation example163
12.8 Method group conversions167
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 operators177
13.4.7 Numeric promotions177
13.4.7.1 General177
13.4.7.2 Unary numeric promotions177
13.4.7.3 Binary numeric promotions178
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 parameters185
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 types189
13.6.3.6 Dependence189
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 Fixing191
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 expressions193
13.6.4 Overload resolution193
13.6.4.1 General193
13.6.4.2 Applicable function member194
13.6.4.3 Better function member194
13.6.4.4 Better conversion from expression196
13.6.4.5 Better conversion from type197
13.6.4.6 Better conversion target197
13.6.4.7 Overloading in generic classes197
13.6.5 Compile-time checking of dynamic member invocation198
13.6.6 Function member invocation199
13.6.6.1 General199
13.6.6.2 Invocations on boxed instances200
13.7 Primary expressions200
13.7.1 General200
13.7.2 Literals201
13.7.3 Simple names201
13.7.3.1 General201
13.7.3.2 Invariant meaning in blocks203
13.7.4 Parenthesized expressions204
13.7.5 Member access204
13.7.5.1 General204
13.7.5.2 Identical simple names and type names206
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 invocations211
13.7.7 Element access211
13.7.7.1 General211
13.7.7.2 Array access212
13.7.7.3 Indexer access212
13.7.8 This access213
13.7.9 Base access214
13.7.10 Postfix increment and decrement operators214
13.7.11 The new operator216
13.7.11.1 General216
13.7.11.2 Object creation expressions216
13.7.11.3 Object initializers218
13.7.11.4 Collection initializers220
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 operator228
13.7.13 The sizeof operator229
13.7.14 The checked and unchecked operators230
13.7.15 Default value expressions232
13.7.16 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 operator264
13.12 Logical operators265
13.12.1 General265
13.12.2 Integer logical operators266
13.12.3 Enumeration logical operators266
13.12.4 Boolean logical operators267
13.12.5 Nullable Boolean & and | operators267
13.13 Conditional logical operators268
13.13.1 General268
13.13.2 Boolean conditional logical operators268
13.13.3 User-defined conditional logical operators269
13.14 The null coalescing operator269
13.15 Conditional operator270
13.16 Anonymous function expressions271
13.16.1 General271
13.16.2 Anonymous function signatures273
13.16.3 Anonymous function bodies273
13.16.4 Overload resolution274
13.16.5 Anonymous functions and dynamic binding275
13.16.6 Outer variables275
13.16.6.1 General275
13.16.6.2 Captured outer variables275
13.16.6.3 Instantiation of local variables276
13.16.7 Evaluation of anonymous function expressions278
13.17 Query expressions278
13.17.1 General278
13.17.2 Ambiguities in query expressions279
13.17.3 Query expression translation279
13.17.3.1 General279
13.17.3.2 Select and groupby clauses with continuations280
13.17.3.3 Explicit range variable types280
13.17.3.4 Degenerate query expressions281
13.17.3.5 From, let, where, join and orderby clauses281
13.17.3.6 Select clauses285
13.17.3.7 Groupby clauses285
13.17.3.8 Transparent identifiers285
13.17.4 The query expression pattern287
13.18 Assignment operators288
13.18.1 General288
13.18.2 Simple assignment288
13.18.3 Compound assignment290
13.18.4 Event assignment291
13.19 Expression292
13.20 Constant expressions292
13.21 Boolean expressions293
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 statement320
14.14 The using statement321
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 directives336
15.6 Namespace member declarations338
15.7 Type declarations338
15.8 Qualified alias member339
15.8.1 General339
15.8.2 Uniqueness of aliases341
16. Classes343
16.1 General343
16.2 Class declarations343
16.2.1 General343
16.2.2 Class modifiers343
16.2.2.1 General343
16.2.2.2 Abstract classes344
16.2.2.3 Sealed classes344
16.2.2.4 Static classes345
16.2.3 Type parameters346
16.2.4 Class base specification347
16.2.4.1 General347
16.2.4.2 Base classes347
16.2.4.3 Interface implementations349
16.2.5 Type parameter constraints350
16.2.6 Class body355
16.2.7 Partial declarations355
16.3 Class members362
16.3.1 General362
16.3.2 The instance type364
16.3.3 Members of constructed types364
16.3.4 Inheritance365
16.3.5 The new modifier367
16.3.6 Access modifiers367
16.3.7 Constituent types367
16.3.8 Static and instance members367
16.3.9 Nested types368
16.3.9.1 General368
16.3.9.2 Fully qualified name369
16.3.9.3 Declared accessibility369
16.3.9.4 Hiding369
16.3.9.5 this access370
16.3.9.6 Access to private and protected members of the containing type371
16.3.9.7 Nested types in generic classes372
16.3.10 Reserved member names372
16.3.10.1 General372
16.3.10.2 Member names reserved for properties373
16.3.10.3 Member names reserved for events373
16.3.10.4 Member names reserved for indexers373
16.3.10.5 Member names reserved for finalizers374
16.4 Constants374
16.5 Fields375
16.5.1 General375
16.5.2 Static and instance fields377
16.5.3 Readonly fields377
16.5.3.1 General377
16.5.3.2 Using static readonly fields for constants377
16.5.3.3 Versioning of constants and static readonly fields377
16.5.4 Volatile fields378
16.5.5 Field initialization379
16.5.6 Variable initializers380
16.5.6.1 General380
16.5.6.2 Static field initialization380
16.5.6.3 Instance field initialization382
16.6 Methods382
16.6.1 General382
16.6.2 Method parameters385
16.6.2.1 General385
16.6.2.2 Value parameters386
16.6.2.3 Reference parameters387
16.6.2.4 Output parameters387
16.6.2.5 Parameter arrays388
16.6.3 Static and instance methods390
16.6.4 Virtual methods391
16.6.5 Override methods393
16.6.6 Sealed methods395
16.6.7 Abstract methods396
16.6.8 External methods397
16.6.9 Partial methods398
16.6.10 Extension methods400
16.6.11 Method body401
16.7 Properties402
16.7.1 General402
16.7.2 Static and instance properties403
16.7.3 Accessors403
16.7.4 Automatically implemented properties408
16.7.5 Accessibility409
16.7.6 Virtual, sealed, override, and abstract accessors410
16.8 Events412
16.8.1 General412
16.8.2 Field-like events414
16.8.3 Event accessors417
16.8.4 Static and instance events419
16.8.5 Virtual, sealed, override, and abstract accessors419
16.9 Indexers419
16.10 Operators423
16.10.1 General423
16.10.2 Unary operators424
16.10.3 Binary operators425
16.10.4 Conversion operators425
16.11 Instance constructors428
16.11.1 General428
16.11.2 Constructor initializers429
16.11.3 Instance variable initializers430
16.11.4 Constructor execution430
16.11.5 Default constructors431
16.12 Static constructors433
16.13 Finalizers435
16.14 Iterators437
16.14.1 General437
16.14.2 Enumerator interfaces437
16.14.3 Enumerable interfaces437
16.14.4 Yield type437
16.14.5 Enumerator objects437
16.14.5.1 General437
16.14.5.2 The MoveNext method438
16.14.5.3 The Current property439
16.14.5.4 The Dispose method439
16.14.6 Enumerable objects440
16.14.6.1 General440
16.14.6.2 The GetEnumerator method440
16.15 Async Functions447
16.15.1 General447
16.15.2 Evaluation of a task-returning async function447
16.15.3 Evaluation of a void-returning async function448
17. Structs449
17.1 General449
17.2 Struct declarations449
17.2.1 General449
17.2.2 Struct modifiers449
17.2.3 Partial modifier450
17.2.4 Struct interfaces450
17.2.5 Struct body450
17.3 Struct members450
17.4 Class and struct differences451
17.4.1 General451
17.4.2 Value semantics451
17.4.3 Inheritance452
17.4.4 Assignment452
17.4.5 Default values452
17.4.6 Boxing and unboxing453
17.4.7 Meaning of this455
17.4.8 Field initializers455
17.4.9 Constructors455
17.4.10 Static constructors456
17.4.11 Automatically implemented properties456
18. Arrays461
18.1 General461
18.2 Array types461
18.2.1 General461
18.2.2 The System.Array type462
18.2.3 Arrays and the generic collection interfaces462
18.3 Array creation463
18.4 Array element access464
18.5 Array members464
18.6 Array covariance464
18.7 Array initializers464
19. Interfaces467
19.1 General467
19.2 Interface declarations467
19.2.1 General467
19.2.2 Interface modifiers467
19.2.3 Variant type parameter lists468
19.2.3.1 General468
19.2.3.2 Variance safety468
19.2.3.3 Variance conversion469
19.2.4 Base interfaces469
19.3 Interface body471
19.4 Interface members471
19.4.1 General471
19.4.2 Interface methods472
19.4.3 Interface properties473
19.4.4 Interface events473
19.4.5 Interface indexers473
19.4.6 Interface member access474
19.5 Fully qualified interface member names475
19.6 Interface implementations476
19.6.1 General476
19.6.2 Explicit interface member implementations477
19.6.3 Uniqueness of implemented interfaces479
19.6.4 Implementation of generic methods480
19.6.5 Interface mapping481
19.6.6 Interface implementation inheritance484
19.6.7 Interface re-implementation486
19.6.8 Abstract classes and interfaces487
20. Enums489
20.1 General489
20.2 Enum declarations489
20.3 Enum modifiers489
20.4 Enum members490
20.5 The System.Enum type492
20.6 Enum values and operations492
21. Delegates493
21.1 General493
21.2 Delegate declarations493
21.3 Delegate Members496
21.4 Delegate compatibility496
21.5 Delegate instantiation497
21.6 Delegate invocation497
22. Exceptions501
22.1 General501
22.2 Causes of exceptions501
22.3 The System.Exception class501
22.4 How exceptions are handled502
22.5 Common exception classes502
23. Attributes505
23.1 General505
23.2 Attribute classes505
23.2.1 General505
23.2.2 Attribute usage505
23.2.3 Positional and named parameters507
23.2.4 Attribute parameter types507
23.3 Attribute specification508
23.4 Attribute instances517
23.4.1 General517
23.4.2 Compilation of an attribute517
23.4.3 Run-time retrieval of an attribute instance517
23.5 Reserved attributes519
23.5.1 General519
23.5.2 The AttributeUsage attribute519
23.5.3 The Conditional attribute520
23.5.3.1 General520
23.5.3.2 Conditional methods520
23.5.3.3 Conditional attribute classes523
23.5.4 The Obsolete attribute524
23.5.5 Caller-info attributes525
23.5.5.1 General525
23.5.5.2 The CallerLineNumber attribute526
23.5.5.3 The CallerFilePath attribute526
23.5.5.4 The CallerMemberName attribute526
23.6 Attributes for interoperation527
24. Unsafe code571
24.1 General571
24.2 Unsafe contexts571
24.3 Pointer types574
24.4 Fixed and moveable variables576
24.5 Pointer conversions577
24.5.1 General577
24.5.2 Pointer arrays578
24.6 Pointers in expressions579
24.6.1 General579
24.6.2 Pointer indirection580
24.6.3 Pointer member access580
24.6.4 Pointer element access581
24.6.5 The address-of operator581
24.6.6 Pointer increment and decrement582
24.6.7 Pointer arithmetic583
24.6.8 Pointer comparison584
24.6.9 The sizeof operator584
24.7 The fixed statement584
24.8 Fixed-size buffers588
24.8.1 General588
24.8.2 Fixed-size buffer declarations588
24.8.3 Fixed-size buffers in expressions589
24.8.4 Definite assignment checking590
24.9 Stack allocation590
Annex A. Grammar595
A.1 General595
A.2 Lexical grammar595
A.2.1 Comments596
A.2.2 Tokens596
A.2.3 Keywords598
A.2.4 Operators and punctuators600
A.2.5 Pre-processing directives600
A.3 Syntactic grammar603
A.3.1 Basic concepts603
A.3.2 Types603
A.3.3 Variables604
A.3.4 Expressions605
A.3.5 Statements611
A.3.6 Namespaces614
A.3.7 Classes615
A.3.8 Structs621
A.3.9 Arrays621
A.3.10 Interfaces622
A.3.11 Enums623
A.3.12 Delegates624
A.3.13 Attributes624
A.4 Grammar extensions for unsafe code625
Annex B. Portability issues629
B.1 General629
B.2 Undefined behavior629
B.3 Implementation-defined behavior629
B.4 Unspecified behavior630
B.5 Other Issues631
Annex C. Standard library635
C.1 General635
C.2 Standard Library Types defined in ISO/IEC 23271635
C.3 Standard Library Types not defined in ISO/IEC 23271:2012644
Annex D. Documentation comments647
D.1 General647
D.2 Introduction647
D.3 Recommended tags648
D.3.1 General648
D.3.2 649
D.3.3 649
D.3.4 650
D.3.5 650
D.3.6 650
D.3.7 651
D.3.8 652
D.3.9 653
D.3.10 653
D.3.11 653
D.3.12 654
D.3.13 654
D.3.14 655
D.3.15 655
D.3.16 655
D.3.17 656
D.3.18 656
D.3.19 656
D.4 Processing the documentation file657
D.4.1 General657
D.4.2 ID string format657
D.4.3 ID string examples658
D.5 An example662
D.5.1 C# source code662
D.5.2 Resulting XML664
Annex E. Bibliography667
ECMA-334
Table of Contents
66
67
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 C).
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.
8 Lexical structure
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 C. 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 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 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 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 types also do not have to be declared before they can be used. For each non-nullable value typeT there is a corresponding nullable 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 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 ( REF _Ref486766991 \r \h \* MERGEFORMAT 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 ( REF _Ref372379001 \r \h 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 ( REF _Ref370394205 \r \h \* MERGEFORMAT 13.9)
x * y
Multiplication
x / y
Division
x % y
Remainder
Additive ( REF _Ref370394205 \r \h \* MERGEFORMAT 13.9)
x + y
Addition, string concatenation, delegate combination
x y
Subtraction, delegate removal
Shift ( REF _Ref493868012 \r \h \* MERGEFORMAT 13.10)
x > y
Shift right
Relational and type testing ( REF _Ref461974763 \r \h \* MERGEFORMAT 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 ( REF _Ref461974763 \r \h \* MERGEFORMAT 13.11)
x == y
Equal
x != y
Not equal
Logical AND ( REF _Ref461974981 \r \h \* MERGEFORMAT 13.12)
x & y
Integer bitwise AND, boolean logical AND
Logical XOR ( REF _Ref461974981 \r \h \* MERGEFORMAT 13.12)
x ^ y
Integer bitwise XOR, boolean logical XOR
Logical OR ( REF _Ref461974981 \r \h \* MERGEFORMAT 13.12)
x | y
Integer bitwise OR, boolean logical OR
Conditional AND ( REF _Ref461975001 \r \h \* MERGEFORMAT 13.13)
x && y
Evaluatesy only ifx is true
Conditional OR ( REF _Ref461975001 \r \h \* MERGEFORMAT 13.13)
x || y
Evaluatesy only ifx is false
Null coalescing ( REF _Ref93160010 \r \h \* MERGEFORMAT 13.14)
X ?? y
Evaluates toy ifx is null, tox otherwise
Conditional ( REF _Ref370394596 \r \h \* MERGEFORMAT 13.15)
x ? y : z
Evaluatesy ifx is true, z ifx is false
Assignment ( REF _Ref370394503 \r \h \* MERGEFORMAT 13.18) or anonymous function ( REF _Ref170644974 \r \h \* MERGEFORMAT 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;
public void Withdraw(decimal amount) {lock (this) {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 in 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 method declaration includes an override modifier, the method overrides an inherited virtual method with the same signature. Whereas a virtual method declaration introduces a new method, an override method declaration specializes an existing inherited virtual method by providing a new implementation of that method.
An abstract method is a virtual method with no implementation. An abstract method is declared with the abstract modifier and is permitted only in a class that is also declared abstract. An abstract method must be overridden in every non-abstract derived class.
The following example declares an abstract class, Expression, which represent