ECMA-334 C# Language Specification
Formatted in one big (1.6Mb) html page by Antony Lesuisse.

(generated from the Jon Jagger splitted version). I took the splitted html catted all the files together using a small python script csharp_join.py.


Table of Contents
1 Scope 2 Conformance 3 References 4 Definitions 5 Notational conventions 6 Acronyms and abbreviations 7 General description 8 Language Overview ......8.1 Getting started ......8.2 Types ............8.2.1 Predefined types ............8.2.2 Conversions ............8.2.3 Array types ............8.2.4 Type system unification ......8.3 Variables and parameters ......8.4 Automatic memory management ......8.5 Expressions ......8.6 Statements ......8.7 Classes ............8.7.1 Constants ............8.7.2 Fields ............8.7.3 Methods ............8.7.4 Properties ............8.7.5 Events ............8.7.6 Operators ............8.7.7 Indexers ............8.7.8 Instance constructors ............8.7.9 Destructors ............8.7.10 Static constructors ............8.7.11 Inheritance ......8.8 Structs ......8.9 Interfaces ......8.10 Delegates ......8.11 Enums ......8.12 Namespaces and assemblies ......8.13 Versioning ......8.14 Attributes 9 Lexical structure ......9.1 Programs ......9.2 Grammars ............9.2.1 Lexical grammar ............9.2.2 Syntactic grammar ......9.3 Lexical analysis ............9.3.1 Line terminators ............9.3.2 Comments ............9.3.3 White space ......9.4 Tokens ............9.4.1 Unicode escape sequences ............9.4.2 Identifiers ............9.4.3 Keywords ............9.4.4 Literals ............9.4.5 Operators and punctuators ......9.5 Pre-processing directives ............9.5.1 Conditional compilation symbols ............9.5.2 Pre-processing expressions ............9.5.3 Declaration directives ............9.5.4 Conditional compilation directives ............9.5.5 Diagnostic directives ............9.5.6 Region control ............9.5.7 Line directives 10 Basic concepts ......10.1 Application startup ......10.2 Application termination ......10.3 Declarations ......10.4 Members ............10.4.1 Namespace members ............10.4.2 Struct members ............10.4.3 Enumeration members ............10.4.4 Class members ............10.4.5 Interface members ............10.4.6 Array members ............10.4.7 Delegate members ......10.5 Member access ............10.5.1 Declared accessibility ............10.5.2 Accessibility domains ............10.5.3 Protected access for instance members ............10.5.4 Accessibility constraints ......10.6 Signatures and overloading ......10.7 Scopes ............10.7.1 Name hiding ......10.8 Namespace and type names ............10.8.1 Fully qualified names ......10.9 Automatic memory management ......10.10 Execution order 11 Types ......11.1 Value types ............11.1.1 Default constructors ............11.1.2 Struct types ............11.1.3 Simple types ............11.1.4 Integral types ............11.1.5 Floating point types ............11.1.6 The decimal type ............11.1.7 The bool type ............11.1.8 Enumeration types ......11.2 Reference types ............11.2.1 Class types ............11.2.2 The object type ............11.2.3 The string type ............11.2.4 Interface types ............11.2.5 Array types ............11.2.6 Delegate types ......11.3 Boxing and unboxing ............11.3.1 Boxing conversions ............11.3.2 Unboxing conversions 12 Variables ......12.1 Variable categories ............12.1.1 Static variables ............12.1.2 Instance variables ............12.1.3 Array elements ............12.1.4 Value parameters ............12.1.5 Reference parameters ............12.1.6 Output parameters ............12.1.7 Local variables ......12.2 Default values ......12.3 Definite assignment ............12.3.1 Initially assigned variables ............12.3.2 Initially unassigned variables ............12.3.3 Precise rules for determining definite assignment ......12.4 Variable references ......12.5 Atomicity of variable references 13 Conversions ......13.1 Implicit conversions ............13.1.1 Identity conversion ............13.1.2 Implicit numeric conversions ............13.1.3 Implicit enumeration conversions ............13.1.4 Implicit reference conversions ............13.1.5 Boxing conversions ............13.1.6 Implicit constant expression conversions ............13.1.7 User-defined implicit conversions ......13.2 Explicit conversions ............13.2.1 Explicit numeric conversions ............13.2.2 Explicit enumeration conversions ............13.2.3 Explicit reference conversions ............13.2.4 Unboxing conversions ............13.2.5 User-defined explicit conversions ......13.3 Standard conversions ............13.3.1 Standard implicit conversions ............13.3.2 Standard explicit conversions ......13.4 User-defined conversions ............13.4.1 Permitted user-defined conversions ............13.4.2 Evaluation of user-defined conversions ............13.4.3 User-defined implicit conversions ............13.4.4 User-defined explicit conversions 14 Expressions ......14.1 Expression classifications ............14.1.1 Values of expressions ......14.2 Operators ............14.2.1 Operator precedence and associativity ............14.2.2 Operator overloading ............14.2.3 Unary operator overload resolution ............14.2.4 Binary operator overload resolution ............14.2.5 Candidate user-defined operators ............14.2.6 Numeric promotions ......14.3 Member lookup ............14.3.1 Base types ......14.4 Function members ............14.4.1 Argument lists ............14.4.2 Overload resolution ............14.4.3 Function member invocation ......14.5 Primary expressions ............14.5.1 Literals ............14.5.2 Simple names ............14.5.3 Parenthesized expressions ............14.5.4 Member access ............14.5.5 Invocation expressions ............14.5.6 Element access ............14.5.7 This access ............14.5.8 Base access ............14.5.9 Postfix increment and decrement operators ............14.5.10 The new operator ............14.5.11 The typeof operator ............14.5.12 The checked and unchecked operators ......14.6 Unary expressions ............14.6.1 Unary plus operator ............14.6.2 Unary minus operator ............14.6.3 Logical negation operator ............14.6.4 Bitwise complement operator ............14.6.5 Prefix increment and decrement operators ............14.6.6 Cast expressions ......14.7 Arithmetic operators ............14.7.1 Multiplication operator ............14.7.2 Division operator ............14.7.3 Remainder operator ............14.7.4 Addition operator ............14.7.5 Subtraction operator ......14.8 Shift operators ......14.9 Relational and type-testing operators ............14.9.1 Integer comparison operators ............14.9.2 Floating-point comparison operators ............14.9.3 Decimal comparison operators ............14.9.4 Boolean equality operators ............14.9.5 Enumeration comparison operators ............14.9.6 Reference type equality operators ............14.9.7 String equality operators ............14.9.8 Delegate equality operators ............14.9.9 The is operator ............14.9.10 The as operator ......14.10 Logical operators ............14.10.1 Integer logical operators ............14.10.2 Enumeration logical operators ............14.10.3 Boolean logical operators ......14.11 Conditional logical operators ............14.11.1 Boolean conditional logical operators ............14.11.2 User-defined conditional logical operators ......14.12 Conditional operator ......14.13 Assignment operators ............14.13.1 Simple assignment ............14.13.2 Compound assignment ............14.13.3 Event assignment ......14.14 Expression ......14.15 Constant expressions ......14.16 Boolean expressions 15 Statements ......15.1 End points and reachability ......15.2 Blocks ............15.2.1 Statement lists ......15.3 The empty statement ......15.4 Labeled statements ......15.5 Declaration statements ............15.5.1 Local variable declarations ............15.5.2 Local constant declarations ......15.6 Expression statements ......15.7 Selection statements ............15.7.1 The if statement ............15.7.2 The switch statement ......15.8 Iteration statements ............15.8.1 The while statement ............15.8.2 The do statement ............15.8.3 The for statement ............15.8.4 The foreach statement ......15.9 Jump statements ............15.9.1 The break statement ............15.9.2 The continue statement ............15.9.3 The goto statement ............15.9.4 The return statement ............15.9.5 The throw statement ......15.10 The try statement ......15.11 The checked and unchecked statements ......15.12 The lock statement ......15.13 The using statement 16 Namespaces ......16.1 Compilation units ......16.2 Namespace declarations ......16.3 Using directives ............16.3.1 Using alias directives ............16.3.2 Using namespace directives ......16.4 Namespace members ......16.5 Type declarations 17 Classes ......17.1 Class declarations ............17.1.1 Class modifiers ............17.1.2 Class base specification ............17.1.3 Class body ......17.2 Class members ............17.2.1 Inheritance ............17.2.2 The new modifier ............17.2.3 Access modifiers ............17.2.4 Constituent types ............17.2.5 Static and instance members ............17.2.6 Nested types ............17.2.7 Reserved member names ......17.3 Constants ......17.4 Fields ............17.4.1 Static and instance fields ............17.4.2 Readonly fields ............17.4.3 Volatile fields ............17.4.4 Field initialization ............17.4.5 Variable initializers ......17.5 Methods ............17.5.1 Method parameters ............17.5.2 Static and instance methods ............17.5.3 Virtual methods ............17.5.4 Override methods ............17.5.5 Sealed methods ............17.5.6 Abstract methods ............17.5.7 External methods ............17.5.8 Method body ............17.5.9 Method overloading ......17.6 Properties ............17.6.1 Static and instance properties ............17.6.2 Accessors ............17.6.3 Virtual ......17.7 Events ............17.7.1 Field-like events ............17.7.2 Event accessors ............17.7.3 Static and instance events ............17.7.4 Virtual ......17.8 Indexers ............17.8.1 Indexer overloading ......17.9 Operators ............17.9.1 Unary operators ............17.9.2 Binary operators ............17.9.3 Conversion operators ......17.10 Instance constructors ............17.10.1 Constructor initializers ............17.10.2 Instance variable initializers ............17.10.3 Constructor execution ............17.10.4 Default constructors ............17.10.5 Private constructors ............17.10.6 Optional instance constructor parameters ......17.11 Static constructors ......17.12 Destructors 18 Structs ......18.1 Struct declarations ............18.1.1 Struct modifiers ............18.1.2 Struct interfaces ............18.1.3 Struct body ......18.2 Struct members ......18.3 Class and struct differences ............18.3.1 Value semantics ............18.3.2 Inheritance ............18.3.3 Assignment ............18.3.4 Default values ............18.3.5 Boxing and unboxing ............18.3.6 Meaning of this ............18.3.7 Field initializers ............18.3.8 Constructors ............18.3.9 Destructors ......18.4 Struct examples ............18.4.1 Database integer type ............18.4.2 Database boolean type 19 Arrays ......19.1 Array types ............19.1.1 The System.Array type ......19.2 Array creation ......19.3 Array element access ......19.4 Array members ......19.5 Array covariance ......19.6 Array initializers 20 Interfaces ......20.1 Interface declarations ............20.1.1 Interface modifiers ............20.1.2 Base interfaces ............20.1.3 Interface body ......20.2 Interface members ............20.2.1 Interface methods ............20.2.2 Interface properties ............20.2.3 Interface events ............20.2.4 Interface indexers ............20.2.5 Interface member access ......20.3 Fully qualified interface member names ......20.4 Interface implementations ............20.4.1 Explicit interface member implementations ............20.4.2 Interface mapping ............20.4.3 Interface implementation inheritance ............20.4.4 Interface re-implementation ............20.4.5 Abstract classes and interfaces 21 Enums ......21.1 Enum declarations ......21.2 Enum modifiers ......21.3 Enum members ......21.4 Enum values and operations 22 Delegates ......22.1 Delegate declarations ......22.2 Delegate instantiation ......22.3 Delegate invocation 23 Exceptions ......23.1 Causes of exceptions ......23.2 The System.Exception class ......23.3 How exceptions are handled ......23.4 Common Exception Classes 24 Attributes ......24.1 Attribute classes ............24.1.1 Attribute usage ............24.1.2 Positional and named parameters ............24.1.3 Attribute parameter types ......24.2 Attribute specification ......24.3 Attribute instances ............24.3.1 Compilation of an attribute ............24.3.2 Run-time retrieval of an attribute instance ......24.4 Reserved attributes ............24.4.1 The AttributeUsage attribute ............24.4.2 The Conditional attribute ............24.4.3 The Obsolete attribute 25 Unsafe code ......25.1 Unsafe contexts ......25.2 Pointer types ......25.3 Fixed and moveable variables ......25.4 Pointer conversions ......25.5 Pointers in expressions ............25.5.1 Pointer indirection ............25.5.2 Pointer member access ............25.5.3 Pointer element access ............25.5.4 The address-of operator ............25.5.5 Pointer increment and decrement ............25.5.6 Pointer arithmetic ............25.5.7 Pointer comparison ............25.5.8 The sizeof operator ......25.6 The fixed statement ......25.7 Stack allocation ......25.8 Dynamic memory allocation


1 ScopeThis clause is informative. This ECMA 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 of C#.
This ECMA 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.
End of informative text.



2 Conformance Paragraph 11
Conformance is of interest to the following audiences: Paragraph 21 As such, conformance is most important, and the bulk of this ECMA Standard is aimed at specifying the characteristics that make C# implementations and C# programs conforming ones. Paragraph 31 The text in this ECMA Standard that specifies requirements is considered normative. 2 All other text in this specification is informative; that is, for information purposes only. 3 Unless stated otherwise, all text is normative. 4 Normative text is further broken into required and conditional categories. 5 Conditionally normative text specifies requirements for a feature such that if that feature is provided, its syntax and semantics must be exactly as specified. Paragraph 41 If any requirement of this ECMA Standard is violated, the behavior is undefined. 2 Undefined behavior is otherwise indicated in this ECMA Standard by the words ''undefined behavior'' or by the omission of any explicit definition of behavior. 3 There is no difference in emphasis among these three; they all describe ''behavior that is undefined.'' 4 A strictly conforming program shall use only those features of the language specified in this ECMA Standard as being required. 5 (This means that a strictly conforming program cannot use any conditionally normative feature.) 6 It shall not produce output dependent on any unspecified, undefined, or implementation-defined behavior. Paragraph 51 A conforming implementation of C# must accept any strictly conforming program. Paragraph 61 A conforming implementation of C# must provide and support all the types, values, objects, properties, methods, and program syntax and semantics described in this ECMA Standard. Paragraph 71 A conforming implementation of C# shall interpret characters in conformance with the Unicode Standard, Version 3.0 or later, and ISO/IEC 10646-1. 2 Conforming implementations must accept Unicode source files encoded with the UTF-8 encoding form. Paragraph 81 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. Paragraph 91 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". Paragraph 101 A conforming implementation of C# is permitted to provide additional types, values, objects, properties, and methods beyond those described in this ECMA Standard, provided they do not alter the behavior of any strictly conforming program. 2 Conforming implementations are required to diagnose programs that use extensions that are ill formed according to this ECMA Standard. 3 Having done so, however; they can compile and execute such programs. 4 (The ability to have extensions implies that a conforming implementation reserves no identifiers other than those explicitly reserved in this ECMA Standard.) Paragraph 111 A conforming implementation of C# shall be accompanied by a document that defines all implementation-defined characteristics, and all extensions. Paragraph 121 A conforming implementation of C# shall support the class library documented in §D. 2 This library is included by reference in this ECMA Standard. Paragraph 131 A conforming program is one that is acceptable to a conforming implementation. 2 (Such a program may contain extensions or conditionally normative features.)


3 References Paragraph 11
The following normative documents contain provisions, which, through reference in this text, constitute provisions of this ECMA Standard. 2 For dated references, subsequent amendments to, or revisions of, any of these publications do not apply. 3 However, parties to agreements based on this ECMA Standard are encouraged to investigate the possibility of applying the most recent editions of the normative documents indicated below. 4 For undated references, the latest edition of the normative document referred to applies. 5 Members of ISO and IEC maintain registers of currently valid ECMA Standards. Paragraph 21 ECMA-335, 1st Edition, December 2001, Common Language Infrastructure (CLI), Partition IV: Base Class Library (BCL), Extended Numerics Library, and Extended Array Library. Paragraph 31 ISO 31.11:1992, Quantities and units -Part 11: Mathematical signs and symbols for use in the physical sciences and technology. Paragraph 41 ISO/IEC 2382.1:1993, Information technology -Vocabulary -Part 1: Fundamental terms. Paragraph 51 ISO/IEC 10646 (all parts), Information technology -Universal Multiple-Octet Coded Character Set (UCS). Paragraph 61 IEC 60559:1989, Binary floating-point arithmetic for microprocessor systems (previously designated IEC 559:1989). 2 (This standard is widely known by its U.S. national designation, ANSI/IEEE Standard 754-1985, IEEE Standard for Binary Floating-Point Arithmetic.) 3 Due to the extremely widespread recognition of IEEE as the name of a form of floating-point representation and arithmetic, this ECMA Standard uses that term instead of its IEC equivalent. Paragraph 71 The Unicode Consortium. 2 The Unicode Standard, Version 3.0, defined by: The Unicode Standard, Version 3.0 (Reading, MA, Addison-Wesley, 2000. 3 ISBN 0-201-61633-5), and Unicode Technical Report #15: Unicode Normalization Forms. The following references are informative. ISO/IEC 9899:1999, Programming languages -C. ISO/IEC 14882:1998, Programming languages -C++. ANSI X3.274-1996, Programming Language REXX. (This document is useful in understanding floating-point decimal arithmetic rules.) End of informative references.


4 Definitions Paragraph 11
For the purposes of this ECMA Standard, the following definitions apply. 2 Other terms are defined where they appear in italic type or on the left side of a syntax rule. 3 Terms explicitly defined in this ECMA Standard are not to be presumed to refer implicitly to similar terms defined elsewhere. 4 Terms not defined in this ECMA Standard are to be interpreted according to ISO/IEC 2382.1. 5 Mathematical symbols not defined in this ECMA Standard are to be interpreted according to ISO 31.11. Paragraph 21 Application -refers to an assembly that has an entry point (§10.1). 2 When an application is run, a new application domain is created. 3 Several different instantiations of an application may exist on the same machine at the same time, and each has its own application domain. Paragraph 31 Application domain -an entity that enables application isolation by acting as a container for application state. 2 An application domain acts as a container and boundary for the types defined in the application and the class libraries it uses. 3 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. 4 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. 5 Implementations are free to provide implementation-specific policy or mechanisms for the creation and destruction of application domains. Paragraph 41 Argument -an expression in the comma-separated list bounded by the parentheses in a method or instance constructor call expression. 2 It is also known as an actual argument. Paragraph 51 Assembly -refers to one or more files that are output by the compiler as a result of program compilation. 2 An assembly is a configured set of loadable code modules and other resources that together implement a unit of functionality. 3 An assembly may contain types, the executable code used to implement these types, and references to other assemblies. 4 The physical representation of an assembly is not defined by this specification. 5 Essentially, an assembly is the output of the compiler. Paragraph 61 Behavior -external appearance or action. Paragraph 71 Behavior, implementation-defined -unspecified behavior where each implementation documents how the choice is made. Paragraph 81 Behavior, undefined -behavior, upon use of a nonportable or erroneous construct or of erroneous data, for which this ECMA Standard imposes no requirements. 2 [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)]. Paragraph 91 Behavior, unspecified -behavior where this ECMA Standard provides two or more possibilities and imposes no further requirements on which is chosen in any instance. Paragraph 101 Class library -refers to an assembly that can be used by other assemblies. 2 Use of a class library does not cause the creation of a new application domain. 3 Instead, a class library is loaded into the application domain that uses it. 4 For instance, when an application uses a class library, that class library is loaded into the application domain for that application. 5 If an application uses a class library A that itself uses a class library B, then both A and B are loaded into the application domain for the application. Paragraph 111 Diagnostic message -a message belonging to an implementation-defined subset of the implementation's output messages. Paragraph 121 Error, compile-time -an error reported during program translation. Paragraph 131 Exception -an error condition that is outside the ordinary expected behavior. Paragraph 141 Implementation -particular 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. Paragraph 151 Namespace -a logical organizational system that provides a way of presenting program elements that are exposed to other programs. Paragraph 161 Parameter -a variable declared as part of a method, instance constructor, or indexer definition, which acquires a value on entry to that method. 2 It is also known as formal parameter. Paragraph 171 Program -refers to one or more source files that are presented to the compiler. 2 Essentially, a program is the input to the compiler. Paragraph 181 Program, valid -a C# program constructed according to the syntax rules and diagnosable semantic rules. Paragraph 191 Program instantiation -the execution of an application. Paragraph 201 Recommended practice -specification that is strongly recommended as being aligned with the intent of the standard, but that may be impractical for some implementations. Paragraph 211 Source file -an ordered sequence of Unicode characters. 2 Source files typically have a one-to-one correspondence with files in a file system, but this correspondence is not required. Paragraph 221 Unsafe code -code 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. 2 Such operations provide functionality such as permitting interfacing with the underlying operating system, accessing a memory-mapped device, or implementing a time-critical algorithm. Paragraph 231 Warning, compile-time -an informational message reported during program translation, that is intended to identify a potentially questionable usage of a program element.


5 Notational conventions Paragraph 11
Lexical and syntactic grammars for C# are interspersed throughout this specification. 2 The lexical grammar defines how characters can be combined to form tokens (§9.4), the minimal lexical elements of the language. 3 The syntactic grammar defines how tokens can be combined to make valid C# programs. Paragraph 21 Grammar productions include both non-terminal and terminal symbols. 2 In grammar productions, non-terminal symbols are shown in italic type, and terminal symbols are shown in a fixed-width font. 3 Each non-terminal is defined by a set of productions. 4 The first line of a set of productions is the name of the non-terminal, followed by a colon. 5 Each successive indented line contains the right-hand side for a production that has the non-terminal symbol as the left-hand side. 6 For example: class-modifier : new public protected internal private abstract sealed defines the class-modifier non-terminal as having seven productions. Paragraph 31 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. 2 This is simply shorthand for listing each of the alternatives on a separate line. 3 For example: decimal-digit : one of 0 1 2 3 4 5 6 7 8 9 is equivalent to: decimal-digit : 0 1 2 3 4 5 6 7 8 9 Paragraph 41 A subscripted suffix "opt", as in identifieropt, is used as shorthand to indicate an optional symbol. 2 The example: for-statement : for ( for-initializeropt ; for-conditionopt ; for-iteratoropt ) embedded-statement is equivalent to: for-statement : for ( ; ; ) embedded-statement for ( for-initializer ; ; ) embedded-statement for ( ; for-condition ; ) embedded-statement for ( ; ; for-iterator ) embedded-statement for ( for-initializer ; for-condition ; ) embedded-statement for ( ; for-condition ; for-iterator ) embedded-statement for ( for-initializer ; ; for-iterator ) embedded-statement for ( for-initializer ; for-condition ; for-iterator ) embedded-statement Paragraph 51 All terminal characters are to be understood as the appropriate Unicode character from the ASCII range, as opposed to any similar-looking characters from other Unicode ranges.


6 Acronyms and abbreviationsThis clause is informative. The following acronyms and abbreviations are used throughout this ECMA 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 "C Sharp". The name C# is written as the LATIN CAPITAL LETTER C (U+0043) followed by the NUMBER SIGN # (U+000D). End of informative text.



7 General descriptionThis clause is informative. This ECMA 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: 1 Front matter (clauses 1-7); 2 Language overview (clause 8); 3 The language syntax, constraints, and semantics (clauses 9-25); 4 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 ECMA Standard. Clauses 2-5, 9-24, the beginning of 25, and the beginning of D form a normative part of this standard; all of clause 25 with the exception of the beginning is conditionally normative; and Brief history, clauses 1, 6-8, annexes A, B, C, and most of D, notes, examples, and the index are informative. Except for whole clauses or annexes that are identified as being informative, informative text that is contained within normative text is indicated in two ways: 1 [Example: The following example... code fragment, possibly with some narrative...end example] 2 [Note: narrative... end note] End of informative text.



8 Language OverviewThis clause is informative. C# (pronounced "C Sharp") is a simple, modern, object oriented, and type-safe programming language. It will immediately be familiar to C and C++ programmers. C# combines the high productivity of Rapid Application Development (RAD) languages and the raw power of C++. The rest of this chapter describes the essential features of the language. While later chapters describe rules and exceptions in a detail-oriented and sometimes mathematical manner, this chapter 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 chapters.



8.1 Getting startedThe canonical "hello, world" program can be written as follows:
using System;  
class Hello  
{  
   static void Main() {  
      Console.WriteLine("hello, world");  
   }  
}  
The source code for a C# program is typically stored in one or more text files with a file extension of .cs, as in hello.cs. Using a command-line compiler, such a program can be compiled with a command line like
csc hello.cs  
which produces an application named hello.exe. The output produced by this application when it is run is:
hello, world  
Close examination of this program is illuminating:
For C and C++ developers, it is interesting to note a few things that do not appear in the "hello, world" program.


8.2 TypesC# supports two kinds of types: value types and reference types. Value types include simple types (e.g., char, int, and float), enum types, and struct types. Reference types include class types, interface types, delegate types, and array types. Value types differ from reference types in that variables of the value types directly contain their data, whereas variables of the reference types store references to 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. The example
using System;  
class Class1  
{  
   public int Value = 0;  
}  
class Test  
{  
   static void Main() {  
      int val1 = 0;  
      int val2 = val1;  
      val2 = 123;  
      Class1 ref1 = new Class1();  
      Class1 ref2 = ref1;  
      ref2.Value = 123;  
      Console.WriteLine("Values: {0}, {1}", val1, val2);  
      Console.WriteLine("Refs: {0}, {1}", ref1.Value, ref2.Value);  
   }  
}  
shows this difference. The output produced is
Values: 0, 123  
Refs: 123, 123  
The assignment to the local variable val1 does not impact the local variable val2 because both local variables are of a value type (the type int) and each local variable of a value type has its own storage. In contrast, the assignment ref2.Value = 123; affects the object that both ref1 and ref2 reference. The lines
Console.WriteLine("Values: {0}, {1}", val1, val2);  
Console.WriteLine("Refs: {0}, {1}", ref1.Value, ref2.Value);  
deserve further comment, as they demonstrate some of the string formatting behavior of Console.WriteLine, which, in fact, takes a variable number of arguments. The first argument is a string, which may contain numbered placeholders like {0} and {1}. Each placeholder refers to a trailing argument with {0} referring to the second argument, {1} referring to the third argument, and so on. Before the output is sent to the console, each placeholder is replaced with the formatted value of its corresponding argument.
Developers can define new value types through enum and struct declarations, and can define new reference types via class, interface, and delegate declarations. The example
using System;  
public enum Color  
{  
   Red, Blue, Green  
}  
public struct Point   
{   
   public int x, y;   
}  
public interface IBase  
{  
   void F();  
}  
public interface IDerived: IBase  
{  
   void G();  
}  
public class A  
{  
   protected virtual void H() {  
      Console.WriteLine("A.H");  
   }  
}  
public class B: A, IDerived   
{  
   public void F() {  
      Console.WriteLine("B.F, implementation of IDerived.F");  
   }  
   public void G() {  
      Console.WriteLine("B.G, implementation of IDerived.G");  
   }  
   override protected void H() {  
      Console.WriteLine("B.H, override of A.H");  
   }  
}  
public delegate void EmptyDelegate();  
shows an example of each kind of type declaration. Later sections describe type declarations in detail.



8.2.1 Predefined typesC# provides a set of predefined types, most of which will be familiar to C and C++ developers. The predefined reference types are object and string. The type object is the ultimate base type of all other types. The type string is used to represent Unicode string values. Values of type string are immutable. The predefined value types include signed and unsigned integral types, floating-point types, and the types bool, char, and decimal. The signed integral types are sbyte, short, int, and long; the unsigned integral types are byte, ushort, uint, and ulong; and the floating-point types are float and double. The bool type is used to represent boolean values: values that are either true or false. The inclusion of bool makes it easier to write self-documenting code, and also helps eliminate the all-too-common C++ coding error in which a developer mistakenly uses "=" when "==" should have been used. In C#, the example
int i = ...;  
F(i);  
if (i = 0)  // Bug: the test should be (i == 0)  
G();  
results in a compile-time error because the expression i = 0 is of type int, and if statements require an expression of type bool.
The char type is used to represent Unicode characters. A variable of type char represents a single 16-bit Unicode character. The decimal type is appropriate for calculations in which rounding errors caused by floating point representations are unacceptable. Common examples include financial calculations such as tax computations and currency conversions. The decimal type provides 28 significant digits. The table below lists the predefined types, and shows how to write literal values for each of them.
Type Description Example
object The ultimate base type of all other types object o = null;
string String type; a string is a sequence of Unicode characters string s = "hello";
sbyte 8-bit signed integral type sbyte val = 12;
short 16-bit signed integral type short val = 12;
int 32-bit signed integral type int val = 12;
long 64-bit signed integral type long val1 = 12;
long val2 = 34L;
byte 8-bit unsigned integral type byte val1 = 12;
ushort 16-bit unsigned integral type ushort val1 = 12;
uint 32-bit unsigned integral type uint val1 = 12;
uint val2 = 34U;
ulong 64-bit unsigned integral type ulong val1 = 12;
ulong val2 = 34U;
ulong val3 = 56L;
ulong val4 = 78UL;
float Single-precision floating point type float val = 1.23F;
double Double-precision floating point type double val1 = 1.23;
double val2 = 4.56D;
bool Boolean type; a bool value is either true or false bool val1 = true;
bool val2 = false;
char Character type; a char value is a Unicode character char val = 'h';
decimal Precise decimal type with 28 significant digits decimal val = 1.23M;
Each of the predefined types is shorthand for a system-provided type. For example, the keyword int refers to the struct System.Int32. As a matter of style, use of the keyword is favored over use of the complete system type name. Predefined value types such as int are treated specially in a few ways but are for the most part treated exactly like other structs. Operator overloading enables developers to define new struct types that behave much like the predefined value types. For instance, a Digit struct can support the same mathematical operations as the predefined integral types, and can define conversions between Digit and predefined types. The predefined types employ operator overloading themselves. For example, the comparison operators == and != have different semantics for different predefined types:
  • Two expressions of type int are considered equal if they represent the same integer value.
  • Two expressions of type object are considered equal if both refer to the same object, or if both are null.
  • Two expressions of type string are considered equal if the string instances have identical lengths and identical characters in each character position, or if both are null.
The example
using System;  
class Test  
{  
   static void Main() {  
      string s = "Test";  
      string t = string.Copy(s);  
      Console.WriteLine(s == t);  
      Console.WriteLine((object)s == (object)t);  
   }  
}  
produces the output
True  
False  
because the first comparison compares two expressions of type string, and the second comparison compares two expressions of type object.



8.2.2 ConversionsThe predefined types also have predefined conversions. For instance, conversions exist between the predefined types int and long. C# differentiates between two kinds of conversions: implicit conversions and explicit conversions. Implicit conversions are supplied for conversions that can safely be performed without careful scrutiny. For instance, the conversion from int to long is an implicit conversion. This conversion always succeeds, and never results in a loss of information. The following example
using System;  
class Test  
{  
   static void Main() {  
      int intValue = 123;  
      long longValue = intValue;  
      Console.WriteLine("{0}, {1}", intValue, longValue);  
   }  
}  
implicitly converts an int to a long.
In contrast, explicit conversions are performed with a cast expression. The example
using System;  
class Test  
{  
   static void Main() {  
      long longValue = Int64.MaxValue;  
      int intValue = (int) longValue;  
      Console.WriteLine("(int) {0} = {1}", longValue, intValue);  
   }  
}  
uses an explicit conversion to convert a long to an int. The output is:
(int) 9223372036854775807 = -1  
because an overflow occurs. Cast expressions permit the use of both implicit and explicit conversions.



8.2.3 Array typesArrays may be single-dimensional or multi-dimensional. Both "rectangular" and "jagged" arrays are supported. Single-dimensional arrays are the most common type. The example
using System;  
class Test  
{  
   static void Main() {  
      int[] arr = new int[5];  
      for (int i = 0; i < arr.Length; i++)  
      arr[i] = i * i;  
      for (int i = 0; i < arr.Length; i++)  
      Console.WriteLine("arr[{0}] = {1}", i, arr[i]);  
   }  
}  
creates a single-dimensional array of int values, initializes the array elements, and then prints each of them out. The output produced is:
arr[0] = 0  
arr[1] = 1  
arr[2] = 4  
arr[3] = 9  
arr[4] = 16  
The type int[] used in the previous example is an array type. Array types are written using a
non-array-type followed by one or more rank specifiers. The example
class Test  
{  
   static void Main() {  
      int[] a1;    // single-dimensional array of int  
      int[,] a2;    // 2-dimensional array of int  
      int[,,] a3;   // 3-dimensional array of int  
      int[][] j2;     // "jagged" array: array of (array of int)  
      int[][][] j3;    // array of (array of (array of int))  
   }  
}  
shows a variety of local variable declarations that use array types with int as the element type. Array types are reference types, and so the declaration of an array variable merely sets aside space for the reference to the array. Array instances are actually created via array initializers and array creation expressions. The example
class Test  
{  
   static void Main() {  
      int[] a1 = new int[] {1, 2, 3};  
      int[,] a2 = new int[,] {{1, 2, 3}, {4, 5, 6}};  
      int[,,] a3 = new int[10, 20, 30];  
      int[][] j2 = new int[3][];  
      j2[0] = new int[] {1, 2, 3};  
      j2[1] = new int[] {1, 2, 3, 4, 5, 6};  
      j2[2] = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9};  
   }  
}  
shows a variety of array creation expressions. The variables a1, a2 and a3 denote rectangular arrays, and the variable j2 denotes a jagged array. It should be no surprise that these terms are based on the shapes of the arrays. Rectangular arrays always have a rectangular shape. Given the length of each dimension of the array, its rectangular shape is clear. For example, the lengths of a3's three dimensions are 10, 20, and 30, respectively, and it is easy to see that this array contains 10*20*30 elements.
In contrast, the variable j2 denotes a "jagged" array, or an "array of arrays". Specifically, j2 denotes an array of an array of int, or a single-dimensional array of type int[]. Each of these int[] variables can be initialized individually, and this allows the array to take on a jagged shape. The example gives each of the int[] arrays a different length. Specifically, the length of j2[0] is 3, the length of j2[1] is 6, and the length of j2[2] is 9. [Note: In C++, an array declared as int x[3][5][7] would be considered a three dimensional rectangular array, while in C#, the declaration int[][][] declares a jagged array type. end note] The element type and shape of an array-including whether it is jagged or rectangular, and the number of dimensions it has-are part of its type. On the other hand, the size of the array-as represented by the length of each of its dimensions-is not part of an array's type. This split is made clear in the language syntax, as the length of each dimension is specified in the array creation expression rather than in the array type. For instance the declaration
int[,,] a3 = new int[10, 20, 30];  
has an array type of int[,,] and an array creation expression of new int[10, 20, 30].
For local variable and field declarations, a shorthand form is permitted so that it is not necessary to re-state the array type. For instance, the example
int[] a1 = new int[] {1, 2, 3};  
can be shortened to
int[] a1 = {1, 2, 3};  
without any change in program semantics.
The context in which an array initializer such as {1, 2, 3} is used determines the type of the array being initialized. The example
class Test  
{  
   static void Main() {  
      short[] a = {1, 2, 3};  
      int[] b = {1, 2, 3};  
      long[] c = {1, 2, 3};  
   }  
}  
shows that the same array initializer syntax can be used for several different array types. Because context is required to determine the type of an array initializer, it is not possible to use an array initializer in an expression context without explicitly stating the type of the array.



8.2.4 Type system unificationC# provides a "unified type system". All types-including value types-derive from the type object. It is possible to call object methods on any value, even values of "primitive" types such as int. The example
using System;  
class Test  
{  
   static void Main() {  
      Console.WriteLine(3.ToString());  
   }  
}  
calls the object-defined ToString method on an integer literal, resulting in the output "3".
The example
class Test  
{  
   static void Main() {  
      int i = 123;  
      object o = i;   // boxing  
      int j = (int) o;  // unboxing  
   }  
}  
is more interesting. An int value can be converted to object and back again to int. This example shows both boxing and unboxing. When a variable of a value type needs to be converted to a reference type, an object box is allocated to hold the value, and the value is copied into the box. Unboxing is just the opposite. When an object box is cast back to its original value type, the value is copied out of the box and into the appropriate storage location.
This type system unification provides value types with the benefits of object-ness without introducing unnecessary overhead. For programs that don't need int values to act like objects, int values are simply 32-bit values. For programs that need int values to behave like objects, this capability is available on demand. This ability to treat value types as objects bridges the gap between value types and reference types that exists in most languages. For example, a Stack class can provide Push and Pop methods that take and return object values.
public class Stack  
{  
   public object Pop() {...}  
   public void Push(object o) {...}  
}  
Because C# has a unified type system, the Stack class can be used with elements of any type, including value types like int.



8.3 Variables and parametersVariables represent storage locations. Every variable has a type that determines what values can be stored in the variable. Local variables are variables that are declared in methods, properties, or indexers. A local variable is defined by specifying a type name and a declarator that specifies the variable name and an optional initial value, as in:
int a;  
int b = 1;  
but it is also possible for a local variable declaration to include multiple declarators. The declarations of a and b can be rewritten as:
int a, b = 1;  
A variable must be assigned before its value can be obtained. The example
class Test  
{  
   static void Main() {  
      int a;  
      int b = 1;  
      int c = a + b; // error, a not yet assigned  
      ...  
   }  
}  
results in a compile-time error because it attempts to use the variable a before it is assigned a value. The rules governing definite assignment are defined in
§12.3. A field (§17.4) is a variable that is associated with a class or struct, or an instance of a class or struct. A field declared with the static modifier defines a static variable, and a field declared without this modifier defines an instance variable. A static field is associated with a type, whereas an instance variable is associated with an instance. The example
using Personnel.Data;  
class Employee  
{  
   private static DataSet ds;  
   public string Name;  
   public decimal Salary;  
   ...  
}  
shows an Employee class that has a private static variable and two public instance variables.
Formal parameter declarations also define variables. There are four kinds of parameters: value parameters, reference parameters, output parameters, and parameter arrays. A value parameter is used for "in" parameter passing, in which the value of an argument is passed into a method, and modifications of the parameter do not impact the original argument. A value parameter refers to its own variable, one that is distinct from the corresponding argument. This variable is initialized by copying the value of the corresponding argument. The example
using System;  
class Test {  
   static void F(int p) {  
      Console.WriteLine("p = {0}", p);  
      p++;  
   }  
   static void Main() {  
      int a = 1;  
      Console.WriteLine("pre:  a = {0}", a);  
      F(a);  
      Console.WriteLine("post: a = {0}", a);  
   }  
}  
shows a method F that has a value parameter named p. The example produces the output:
pre:  a = 1  
p = 1  
post: a = 1  
even though the value parameter p is modified.
A reference parameter is used for "by reference" parameter passing, in which the parameter acts as an alias for a caller-provided argument. A reference parameter does not itself define a variable, but rather refers to the variable of the corresponding argument. Modifications of a reference parameter impact the corresponding argument. A reference parameter is declared with a ref modifier. The example
using System;  
class Test {  
   static void Swap(ref int a, ref int b) {  
      int t = a;  
      a = b;  
      b = t;  
   }  
   static void Main() {  
      int x = 1;  
      int y = 2;  
      
      Console.WriteLine("pre:  x = {0}, y = {1}", x, y);  
      Swap(ref x, ref y);  
      Console.WriteLine("post: x = {0}, y = {1}", x, y);  
   }  
}  
shows a Swap method that has two reference parameters. The output produced is:
pre:  x = 1, y = 2  
post: x = 2, y = 1  
The ref keyword must be used in both the declaration of the formal parameter and in uses of it. The use of ref at the call site calls special attention to the parameter, so that a developer reading the code will understand that the value of the argument could change as a result of the call. 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 an out modifier. The example
using System;  
class Test {  
   static void Divide(int a, int b, out int result, out int remainder) {  
      result = a / b;  
      remainder = a % b;  
   }  
   static void Main() {  
      for (int i = 1; i < 10; i++)  
      for (int j = 1; j < 10; j++) {  
         int ans, r;  
         Divide(i, j, out ans, out r);  
         Console.WriteLine("{0} / {1} = {2}r{3}", i, j, ans, r);  
      }  
   }  
}  
shows a Divide method that includes two output parameters-one for the result of the division and another for the remainder.
For value, reference, and output parameters, there is a one-to-one correspondence between caller-provided arguments and the parameters used to represent them. A parameter array enables a many-to-one relationship: many arguments can be represented by a single parameter array. In other words, parameter arrays enable variable length argument lists. A parameter array is declared with a params modifier. There can be only one parameter array for a given method, and it must always be the last parameter specified. The type of a parameter array is always a single dimensional array type. A caller can either pass a single argument of this array type, or any number of arguments of the element type of this array type. For instance, the example
using System;  
class Test  
{  
   static void F(params int[] args) {  
      Console.WriteLine("# of arguments: {0}", args.Length);  
      for (int i = 0; i < args.Length; i++)  
      Console.WriteLine("\targs[{0}] = {1}", i, args[i]);  
   }  
   static void Main() {  
      F();  
      F(1);  
      F(1, 2);  
      F(1, 2, 3);  
      F(new int[] {1, 2, 3, 4});  
   }  
}  
shows a method F that takes a variable number of int arguments, and several invocations of this method. The output is:
# of arguments: 0  
# of arguments: 1  
args[0] = 1  
# of arguments: 2  
args[0] = 1  
args[1] = 2  
# of arguments: 3  
args[0] = 1  
args[1] = 2  
args[2] = 3  
# of arguments: 4  
args[0] = 1  
args[1] = 2  
args[2] = 3  
args[3] = 4  
Most of the examples presented in this introduction use the WriteLine method of the Console class. The argument substitution behavior of this method, as exhibited in the example
int a = 1, b = 2;  
Console.WriteLine("a = {0}, b = {1}", a, b);  
is accomplished using a parameter array. The WriteLine method provides several overloaded methods for the common cases in which a small number of arguments are passed, and one method that uses a parameter array.
namespace System  
{  
   public class Console  
   {  
      public static void WriteLine(string s) {...}  
      public static void WriteLine(string s, object a) {...}  
      public static void WriteLine(string s, object a, object b) {...}  
      ...  
      public static void WriteLine(string s, params object[] args) {...}  
   }  
}  



8.4 Automatic memory managementManual memory management requires developers to manage the allocation and de-allocation of blocks of memory. Manual memory management can be both time-consuming and difficult. In C#, automatic memory management is provided so that developers are freed from this burdensome task. In the vast majority of cases, automatic memory management increases code quality and enhances developer productivity without negatively impacting either expressiveness or performance. The example
using System;  
public class Stack  
{  
   private Node first = null;  
   public bool Empty {  
      get {  
         return (first == null);  
      }  
   }  
   public object Pop() {  
      if (first == null)   
      throw new Exception("Can't Pop from an empty Stack.");  
      else {  
         object temp = first.Value;  
         first = first.Next;  
         return temp;  
      }  
   }  
   public void Push(object o) {  
      first = new Node(o, first);  
   }  
   class Node  
   {  
      public Node Next;  
      public object Value;  
      public Node(object value): this(value, null) {}  
      public Node(object value, Node next) {  
         Next = next;  
         Value = value;  
      }  
   }  
}  
shows a Stack class implemented as a linked list of Node instances. Node instances are created in the Push method and are garbage collected when no longer needed. A Node instance becomes eligible for garbage collection when it is no longer possible for any code to access it. For instance, when an item is removed from the Stack, the associated Node instance becomes eligible for garbage collection.
The example
class Test  
{  
   static void Main() {  
      Stack s = new Stack();  
      for (int i = 0; i < 10; i++)  
      s.Push(i);  
      s = null;  
   }  
}  
shows code that uses the Stack class. A Stack is created and initialized with 10 elements, and then assigned the value null. Once the variable s is assigned null, the Stack and the associated 10 Node instances become eligible for garbage collection. The garbage collector is permitted to clean up immediately, but is not required to do so.
The garbage collector underlying C# may work by moving objects around in memory, but this motion is invisible to most C# developers. For developers who are generally content with automatic memory management but sometimes need fine-grained control or that extra bit of performance, C# provides the ability to write "unsafe" code. Such code can deal directly with pointer types and object addresses, however, C# requires the programmer to fix objects to temporarily prevent the garbage collector from moving them. This "unsafe" code feature is in fact a "safe" feature from the perspective of both developers and users. Unsafe code must be clearly marked in the code with the modifier unsafe, so developers can't possibly use unsafe language features accidentally, and the compiler and the execution engine work together to ensure that unsafe code cannot masquerade as safe code. These restrictions limit the use of unsafe code to situations in which the code is trusted. The example
using System;  
class Test  
{  
   static void WriteLocations(byte[] arr) {  
      unsafe {  
         fixed (byte* pArray = arr) {  
            byte* pElem = pArray;  
            for (int i = 0; i < arr.Length; i++) {  
               byte value = *pElem;  
               Console.WriteLine("arr[{0}] at 0x{1:X} is {2}",  
               i, (uint)pElem, value);  
               pElem++;  
            }  
         }  
      }  
   }  
   static void Main() {  
      byte[] arr = new byte[] {1, 2, 3, 4, 5};  
      WriteLocations(arr);  
   }  
}  
shows an unsafe block in a method named WriteLocations that fixes an array instance and uses pointer manipulation to iterate over the elements. The index, value, and location of each array element are written to the console. One possible example of output is:
arr[0] at 0x8E0360 is 1  
arr[1] at 0x8E0361 is 2  
arr[2] at 0x8E0362 is 3  
arr[3] at 0x8E0363 is 4  
arr[4] at 0x8E0364 is 5  
but, of course, the exact memory locations may be different in different executions of the application.



8.5 ExpressionsC# includes unary operators, binary operators, and one ternary operator. The following table summarizes the operators, listing them in order of precedence from highest to lowest:
Section Category Operators
14.5 Primary x.y f(x) [x] x++ x-- new
typeof checked unchecked
14.6 Unary + - ! ~ ++x --x (T)x
14.7 Multiplicative * / %
14.7 Additive + -
14.8 Shift << >>
14.9 Relational and
type-testing
< > <= >= is as
14.9 Equality == !=
14.10 Logical AND &
14.10 Logical XOR ^
14.10 Logical OR |
14.11 Conditional AND &&
14.11 Conditional OR ||
14.12 Conditional ?:
14.13 Assignment = *= /= %= +-= -= <<= >>= &= ^= |=
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 multiplies y by z and then adds the result to x, but (x + y) * z first adds x and y and then multiplies the result by z.



8.6 StatementsC# borrows most of its statements directly from C and C++, though there are some noteworthy additions and modifications. The table below lists the kinds of statements that can be used, and provides an example for each.
Statement Example
Statement lists and block statements
static void Main() {
    F();
    G();
    {
        H();
        I();
    }
}
Labeled statements and goto statements
static void Main(string[] args) {
    if (args.Length == 0)
        goto done;
    Console.WriteLine(args.Length);

done:
    Console.WriteLine("Done");
}
Local constant declarations
static void Main() {
    const float pi = 3.14f;
    const int r = 123;
    Console.WriteLine(pi * r * r);
}
Local variable declarations
static void Main() {
    int a;
    int b = 2, c = 3;
    a = 1;
    Console.WriteLine(a + b + c);
}
Expression statements
static int F(int a, int b) {
    return a + b;
}
static void Main() {
    F(1, 2); // Expression statement
}
if statements
static void Main(string[] args) {
    if (args.Length == 0)
        Console.WriteLine("No args");
    else
        Console.WriteLine("Args");
}
switch statements
static void Main(string[] args) {
    switch (args.Length) {
        case 0:
            Console.WriteLine("No args");
            break;
        case 1:
            Console.WriteLine("One arg");
            break;
        default:
            int n = args.Length;
            Console.WriteLine("{0} args", n);
            break;
    }
}
while statements
static void Main(string[] args) {
    int i = 0;
    while (i < args.Length) {
        Console.WriteLine(args[i]);
        i++;
    }
}
do statements
static void Main() {
    string s;
    do { s = Console.ReadLine(); }
    while (s != "Exit");
}
for statements
static void Main(string[] args) {
    for (int i = 0; i < args.Length; i++)
        Console.WriteLine(args[i]);
}
foreach statements
static void Main(string[] args) {
    foreach (string s in args)
        Console.WriteLine(s);
}
break statements
static void Main(string[] args) {
    int i = 0;
    while (true) {
        if (i == args.Length)
            break;
        Console.WriteLine(args[i++]);
    }
}
continue statements
static void Main(string[] args) {
    int i = 0;
    while (true) {
        Console.WriteLine(args[i++]);
        if (i < args.Length)
            continue;
        break;
    }
}
return statements
static int F(int a, int b) {
    return a + b;
}
static void Main() {
    Console.WriteLine(F(1, 2));
    return;
}
throw statements and try statements
static int F(int a, int b) {
    if (b == 0)
        throw new Exception("Divide by zero");
    return a / b;
}
static void Main() {
    try {
        Console.WriteLine(F(5, 0));
    }
    catch(Exception e) {
        Console.WriteLine("Error");
    }
}
checked and unchecked statements
static void Main() {
    int x = Int32.MaxValue;
    Console.WriteLine(x + 1);     // Overflow
    checked {
        Console.WriteLine(x + 1); // Exception
    }
    unchecked {
        Console.WriteLine(x + 1); // Overflow
    }
}
lock statements
static void Main() {
    A a = ...;
    lock(a) {
        a.P = a.P + 1;
    }
}
using statements
static void Main() {
    using (Resource r = new Resource()) {
        r.F();
    }
}



8.7 ClassesClass declarations define new reference types. A class can inherit from another class, and can implement interfaces. Class members can include constants, fields, methods, properties, events, indexers, operators, instance constructors, destructors, static constructors, and nested type declarations. Each member has an associated accessibility (
§10.5), 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 table below.
Form Intuitive meaning
public Access not limited
protected Access limited to the containing class or types derived from the containing class
internal Access limited to this program
protected
internal
Access limited to this program or types derived from the containing class
private Access limited to the containing type
The example
using System;  
class MyClass  
{  
   public MyClass() {  
      Console.WriteLine("Instance constructor");  
   }  
   public MyClass(int value) {  
      MyField = value;  
      Console.WriteLine("Instance constructor");  
   }  
   ~MyClass() {  
      Console.WriteLine("Destructor");  
   }  
   public const int MyConst = 12;  
   public int MyField = 34;  
   public void MyMethod(){  
      Console.WriteLine("MyClass.MyMethod");  
   }  
   public int MyProperty {  
      get {  
         return MyField;  
      }  
      set {  
         MyField = value;  
      }  
   }  
   public int this[int index] {  
      get {  
         return 0;  
      }  
      set {  
         Console.WriteLine("this[{0}] = {1}", index, value);  
      }  
   }  
   public event EventHandler MyEvent;  
   public static MyClass operator+(MyClass a, MyClass b) {  
      return new MyClass(a.MyField + b.MyField);  
   }  
   internal class MyNestedClass  
   {}  
}  
shows a class that contains each kind of member. The example
class Test  
{  
   static void Main() {  
      // Instance constructor usage  
      MyClass a = new MyClass();  
      MyClass b = new MyClass(123);  
      // Constant usage  
      Console.WriteLine("MyConst = {0}", MyClass.MyConst);  
      // Field usage  
      a.MyField++;  
      Console.WriteLine("a.MyField = {0}", a.MyField);  
      // Method usage  
      a.MyMethod();  
      // Property usage  
      a.MyProperty++;  
      Console.WriteLine("a.MyProperty = {0}", a.MyProperty);  
      // Indexer usage  
      a[3] = a[1] = a[2];  
      Console.WriteLine("a[3] = {0}", a[3]);  
      // Event usage  
      a.MyEvent += new EventHandler(MyHandler);  
      // Overloaded operator usage  
      MyClass c = a + b;  
   }  
   static void MyHandler(object sender, EventArgs e) {  
      Console.WriteLine("Test.MyHandler");  
   }  
   internal class MyNestedClass  
   {}  
}  
shows uses of these members.



8.7.1 ConstantsA constant is a class member that represents a constant value: a value that can be computed at compile-time. Constants are permitted to depend on other constants within the same program as long as there are no circular dependencies. The rules governing constant expressions are defined in
§14.15. The example
class Constants  
{  
   public const int A = 1;  
   public const int B = A + 1;  
}  
shows a class named Constants that has two public constants. Even though constants are considered static members, a constant declaration neither requires nor allows the modifier static. Constants can be accessed through the class, as in
using System;  
class Test  
{  
   static void Main() {  
      Console.WriteLine("{0}, {1}", Constants.A, Constants.B);  
   }  
}  
which prints out the values of Constants.A and Constants.B, respectively.



8.7.2 FieldsA field is a member that represents a variable associated with an object or class. The example
class Color  
{  
   internal ushort redPart;  
   internal ushort bluePart;  
   internal ushort greenPart;  
   public Color(ushort red, ushort blue, ushort green) {  
      redPart = red;  
      bluePart = blue;  
      greenPart = green;  
   }  
   public static Color Red = new Color(0xFF, 0, 0);  
   public static Color Blue = new Color(0, 0xFF, 0);  
   public static Color Green = new Color(0, 0, 0xFF);  
   public static Color White = new Color(0xFF, 0xFF, 0xFF);  
}  
shows a Color class that has internal instance fields named redPart, bluePart, and greenPart, and static fields named Red, Blue, Green, and White The use of static fields in this manner is not ideal. The fields are initialized at some point before they are used, but after this initialization there is nothing to stop a client from changing them. Such a modification could cause unpredictable errors in other programs that use Color and assume that the values do not change. Readonly fields can be used to prevent such problems. Assignments to a readonly field can only occur as part of the declaration, or in an instance constructor or static constructor in the same class. A static readonly field can be assigned in a static constructor, and a non-static readonly field can be assigned in an instance constructor. Thus, the Color class can be enhanced by adding the modifier readonly to the static fields:
class Color  
{  
   internal ushort redPart;  
   internal ushort bluePart;  
   internal ushort greenPart;  
   public Color(ushort red, ushort blue, ushort green) {  
      redPart = red;  
      bluePart = blue;  
      greenPart = green;  
   }  
   public static readonly Color Red = new Color(0xFF, 0, 0);  
   public static readonly Color Blue = new Color(0, 0xFF, 0);  
   public static readonly Color Green = new Color(0, 0, 0xFF);  
   public static readonly Color White = new Color(0xFF, 0xFF, 0xFF);  
}  



8.7.3 MethodsA method is a member that implements a computation or action that can be performed by an object or class. Methods have a (possibly empty) list of formal parameters, a return value (unless the method's
return-type is void), and are either static or non-static. Static methods are accessed through the class. Non-static methods, which are also called instance methods, are accessed through instances of the class. The example
using System;  
public class Stack  
{  
   public static Stack Clone(Stack s) {...}  
   public static Stack Flip(Stack s) {...}  
   public object Pop() {...}  
   public void Push(object o) {...}  
   public override string ToString() {...}  
   ...  
}  
class Test  
{  
   static void Main() {  
      Stack s = new Stack();  
      for (int i = 1; i < 10; i++)  
      s.Push(i);  
      Stack flipped = Stack.Flip(s);  
      Stack cloned = Stack.Clone(s);  
      Console.WriteLine("Original stack: " + s.ToString());  
      Console.WriteLine("Flipped stack: " + flipped.ToString());  
      Console.WriteLine("Cloned stack: " + cloned.ToString());  
   }  
}  
shows a Stack that has several static methods (Clone and Flip) and several instance methods (Pop, Push, and ToString). Methods can be overloaded, which means that multiple methods may have the same name so long as they have unique signatures. The signature of a method consists of the name of the method and the number, modifiers, and types of its formal parameters. The signature of a method does not include the return type. The example
using System;  
class Test  
{  
   static void F() {  
      Console.WriteLine("F()");  
   }  
   static void F(object o) {  
      Console.WriteLine("F(object)");  
   }  
   static void F(int value) {  
      Console.WriteLine("F(int)");  
   }  
   static void F(ref int value) {  
      Console.WriteLine("F(ref int)");  
   }  
   static void F(int a, int b) {  
      Console.WriteLine("F(int, int)");  
   }  
   static void F(int[] values) {  
      Console.WriteLine("F(int[])");  
   }  
   static void Main() {  
      F();  
      F(1);  
      int i = 10;  
      F(ref i);  
      F((object)1);  
      F(1, 2);  
      F(new int[] {1, 2, 3});  
   }  
}  
shows a class with a number of methods called F. The output produced is
F()  
F(int)  
F(ref int)  
F(object)  
F(int, int)  
F(int[])  



8.7.4 PropertiesA property is a member that provides access to a characteristic of an object or a class. Examples of properties include the length of a string, the size of a font, the caption of a window, the name of a customer, and so on. Properties are a natural extension of fields. Both are named members with associated types, and the syntax for accessing fields and properties is the same. However, unlike fields, properties do not denote storage locations. Instead, properties have accessors that specify the statements to be executed when their values are read or written. Properties are defined with property declarations. The first part of a property declaration looks quite similar to a field declaration. The second part includes a get accessor and/or a set accessor. In the example below, the Button class defines a Caption property.
public class Button   
{  
   private string caption;  
   public string Caption {  
      get {  
         return caption;  
      }  
      set {  
         caption = value;  
         Repaint();  
      }  
   }  
}  
Properties that can be both read and written, such as Caption, include both get and set accessors. The get accessor is called when the property's value is read; the set accessor is called when the property's value is written. In a set accessor, the new value for the property is made available via an implicit parameter named value. The declaration of properties is relatively straightforward, but the real value of properties is seen when they are used. For example, the Caption property can be read and written in the same way that fields can be read and written:
Button b = new Button();  
b.Caption = "ABC";    // set; causes repaint  
string s = b.Caption;  // get  
b.Caption += "DEF";    // get & set; causes repaint  



8.7.5 EventsAn event is a member that enables an object or class to provide notifications. A class defines an event by providing an event declaration (which resembles a field declaration, though with an added event keyword) and an optional set of event accessors. The type of this declaration must be a delegate type. An instance of a delegate type encapsulates one or more callable entities. For instance methods, a callable entity consists of an instance and a method on that instance. For static methods, a callable entity consists of just a method. Given a delegate instance and an appropriate set of arguments, one can invoke all of that delegate instance's methods with that set of arguments. In the example
public delegate void EventHandler(object sender, System.EventArgs e);  
public class Button   
{  
   public event EventHandler Click;  
   public void Reset() {  
      Click = null;  
   }  
}  
the Button class defines a Click event of type EventHandler. Inside the Button class, the Click member is exactly like a private field of type EventHandler. However, outside the Button class, the Click member can only be used on the left-hand side of the += and -= operators. The += operator adds a handler for the event, and the -= operator removes a handler for the event. The example
using System;  
public class Form1   
{  
   public Form1() {  
      // Add Button1_Click as an event handler for Button1's Click event  
      Button1.Click += new EventHandler(Button1_Click);  
   }  
   Button Button1 = new Button();  
   void Button1_Click(object sender, EventArgs e) {  
      Console.WriteLine("Button1 was clicked!");  
   }  
   public void Disconnect() {  
      Button1.Click -= new EventHandler(Button1_Click);  
   }  
}  
shows a Form1 class that adds Button1_Click as an event handler for Button1's Click event. In the Disconnect method, that event handler is removed.
For a simple event declaration such as
public event EventHandler Click;  
the compiler automatically provides the implementation underlying the += and -= operators.
An implementer who wants more control can get it by explicitly providing add and remove accessors. For example, the Button class could be rewritten as follows:
public class Button   
{  
   private EventHandler handler;  
   public event EventHandler Click {  
      add { handler += value; }  
      
      remove { handler -= value; }  
   }  
}  
This change has no effect on client code, but allows the Button class more implementation flexibility. For example, the event handler for Click need not be represented by a field.



8.7.6 OperatorsAn operator is a member that defines the meaning of an expression operator that can be applied to instances of the class. There are three kinds of operators that can be defined: unary operators, binary operators, and conversion operators. The following example defines a Digit type that represents decimal digits-integral values between 0 and 9.
using System;  
public struct Digit  
{  
   byte value;  
   public Digit(byte value) {  
      if (value < 0 || value > 9) throw new ArgumentException();  
      this.value = value;  
   }  
   public Digit(int value): this((byte) value) {}  
   public static implicit operator byte(Digit d) {  
      return d.value;  
   }  
   public static explicit operator Digit(byte b) {  
      return new Digit(b);  
   }  
   public static Digit operator+(Digit a, Digit b) {  
      return new Digit(a.value + b.value);  
   }  
   public static Digit operator-(Digit a, Digit b) {  
      return new Digit(a.value - b.value);  
   }  
   public static bool operator==(Digit a, Digit b) {  
      return a.value == b.value;  
   }  
   public static bool operator!=(Digit a, Digit b) {  
      return a.value != b.value;  
   }  
   public override bool Equals(object value) {  
      if (value == null) return false;  
      if (GetType() == value.GetType()) return this == (Digit)value;  
   return false;  }  
   public override int GetHashCode() {  
      return value.GetHashCode();  
   }  
   public override string ToString() {  
      return value.ToString();  
   }  
}  
class Test  
{  
   static void Main() {  
      Digit a = (Digit) 5;  
      Digit b = (Digit) 3;  
      Digit plus = a + b;  
      Digit minus = a - b;  
      bool equals = (a == b);  
      Console.WriteLine("{0} + {1} = {2}", a, b, plus);  
      Console.WriteLine("{0} - {1} = {2}", a, b, minus);  
      Console.WriteLine("{0} == {1} = {2}", a, b, equals);  
   }  
}  
The Digit type defines the following operators:
  • An implicit conversion operator from Digit to byte.
  • An explicit conversion operator from byte to Digit.
  • An addition operator that adds two Digit values and returns a Digit value.
  • A subtraction operator that subtracts one Digit value from another, and returns a Digit value.
  • The equality (==) and inequality (!=) operators, which compare two Digit values.



8.7.7 IndexersAn indexer is a member that enables an object to be indexed in the same way as an array. Whereas properties enable field-like access, indexers enable array-like access. As an example, consider the Stack class presented earlier. The designer of this class might want to expose array-like access so that it is possible to inspect or alter the items on the stack without performing unnecessary Push and Pop operations. That is, class Stack is implemented as a linked list, but it also provides the convenience of array access. Indexer declarations are similar to property declarations, with the main differences being that indexers are nameless (the "name" used in the declaration is this, since this is being indexed) and that indexers include indexing parameters. The indexing parameters are provided between square brackets. The example
using System;  
public class Stack  
{  
   private Node GetNode(int index) {  
      Node temp = first;   
      while (index > 0) {  
         temp = temp.Next;  
         index--;  
      }  
      return temp;  
   }  
   public object this[int index] {  
      get {  
         if (!ValidIndex(index))  
         throw new Exception("Index out of range.");  
         else  
         return GetNode(index).Value;  
      }  
      set {  
         if (!ValidIndex(index))  
         throw new Exception("Index out of range.");  
         else  
         GetNode(index).Value = value;  
      }  
   }  
   ...  
}  
class Test  
{  
   static void Main() {  
      Stack s = new Stack();  
      s.Push(1);  
      s.Push(2);  
      s.Push(3);  
      s[0] = 33;  // Changes the top item from 3 to 33  
      s[1] = 22;  // Changes the middle item from 2 to 22  
      s[2] = 11;  // Changes the bottom item from 1 to 11  
   }  
}  
shows an indexer for the Stack class.



8.7.8 Instance constructorsAn instance constructor is a member that implements the actions required to initialize an instance of a class. The example
using System;  
class Point  
{  
   public double x, y;  
   public Point() {  
      this.x = 0;  
      this.y = 0;  
   }  
   public Point(double x, double y) {  
      this.x = x;  
      this.y = y;  
   }  
   public static double Distance(Point a, Point b) {  
      double xdiff = a.x - b.x;  
      double ydiff = a.y - b.y;  
      return Math.Sqrt(xdiff * xdiff + ydiff * ydiff);  
   }  
   public override string ToString() {  
      return string.Format("({0}, {1})", x, y);  
   }  
}  
class Test  
{  
   static void Main() {  
      Point a = new Point();  
      Point b = new Point(3, 4);  
      double d = Point.Distance(a, b);  
      Console.WriteLine("Distance from {0} to {1} is {2}", a, b, d);  
   }  
}  
shows a Point class that provides two public instance constructors, one of which takes no arguments, while the other takes two double arguments.
If no instance constructor is supplied for a class, then an empty one with no parameters is automatically provided.



8.7.9 DestructorsA destructor is a member that implements the actions required to destruct an instance of a class. Destructors cannot have parameters, they cannot have accessibility modifiers, and they cannot be called explicitly. The destructor for an instance is called automatically during garbage collection. The example
using System;  
class Point  
{  
   public double x, y;  
   public Point(double x, double y) {  
      this.x = x;  
      this.y = y;  
   }  
   ~Point() {  
      Console.WriteLine("Destructed {0}", this);  
   }  
   public override string ToString() {  
      return string.Format("({0}, {1})", x, y);  
   }  
}  
shows a Point class with a destructor.



8.7.10 Static constructorsA static constructor is a member that implements the actions required to initialize a class. Static constructors cannot have parameters, they cannot have accessibility modifiers, and they cannot be called explicitly. The static constructor for a class is called automatically. The example
using Personnel.Data;  
class Employee  
{  
   private static DataSet ds;  
   static Employee() {  
      ds = new DataSet(...);  
   }  
   public string Name;  
   public decimal Salary;  
   ...  
}  
shows an Employee class with a static constructor that initializes a static field.



8.7.11 InheritanceClasses support single inheritance, and the type object is the ultimate base class for all classes. The classes shown in earlier examples all implicitly derive from object. The example
using System;  
class A  
{  
   public void F() { Console.WriteLine("A.F"); }  
}  
shows a class A that implicitly derives from object. The example
class B: A  
{  
   public void G() { Console.WriteLine("B.G"); }  
}  
class Test  
{  
   static void Main() {  
      B b = new B();  
      b.F();    // Inherited from A  
      b.G();      // Introduced in B  
      
      A a = b;     // Treat a B as an A  
      a.F();  
   }  
}  
shows a class B that derives from A. The class B inherits A's F method, and introduces a G method of its own.
Methods, properties, and indexers can be virtual, which means that their implementation can be overridden in derived classes. The example
using System;  
class A  
{  
   public virtual void F() { Console.WriteLine("A.F"); }  
}  
class B: A  
{  
   public override void F() {   
      base.F();  
      Console.WriteLine("B.F");   
   }  
}  
class Test  
{  
   static void Main() {  
      B b = new B();  
      b.F();  
      A a = b;   
      a.F();  
   }  
}   
shows a class A with a virtual method F, and a class B that overrides F. The overriding method in B contains a call, base.F(), which calls the overridden method in A.
A class can indicate that it is incomplete, and is intended only as a base class for other classes, by including the modifier abstract. Such a class is called an abstract class. An abstract class can specify abstract members-members that a non-abstract derived class must implement. The example
using System;  
abstract class A  
{  
   public abstract void F();  
}  
class B: A  
{  
   public override void F() { Console.WriteLine("B.F"); }  
}  
class Test  
{  
   static void Main() {  
      B b = new B();  
      b.F();  
      A a = b;  
      a.F();  
   }  
}  
introduces an abstract method F in the abstract class A. The non-abstract class B provides an implementation for this method.



8.8 StructsThe list of similarities between classes and structs is long-structs can implement interfaces, and can have the same kinds of members as classes. Structs differ from classes in several important ways, however: structs are value types rather than reference types, and inheritance is not supported for structs. Struct values are stored "on the stack" or "in-line". Careful programmers can sometimes enhance performance through judicious use of structs. For example, the use of a struct rather than a class for a Point can make a large difference in the number of memory allocations performed at run time. The program below creates and initializes an array of 100 points. With Point implemented as a class, 101 separate objects are instantiated-one for the array and one each for the 100 elements.
class Point  
{  
   public int x, y;  
   public Point(int x, int y) {  
      this.x = x;  
      this.y = y;  
   }  
}  
class Test  
{  
   static void Main() {  
      Point[] points = new Point[100];  
      for (int i = 0; i < 100; i++)  
      points[i] = new Point(i, i*i);  
   }  
}  
If Point is instead implemented as a struct, as in
struct Point  
{  
   public int x, y;  
   public Point(int x, int y) {  
      this.x = x;  
      this.y = y;  
   }  
}  
only one object is instantiated-the one for the array. The Point instances are allocated in-line within the array. This optimization can be misused. Using structs instead of classes can also make an application run slower or take up more memory, as passing a struct instance by value causes a copy of that struct to be created.



8.9 InterfacesAn interface defines a contract. A class or struct that implements an interface must adhere to its contract. Interfaces can contain methods, properties, events, and indexers as members. The example
interface IExample  
{  
   string this[int index] { get; set; }  
   event EventHandler E;  
   void F(int value);  
   string P { get; set; }  
}  
public delegate void EventHandler(object sender, EventArgs e);  
shows an interface that contains an indexer, an event E, a method F, and a property P.
Interfaces may employ multiple inheritance. In the example
interface IControl  
{  
   void Paint();  
}  
interface ITextBox: IControl  
{  
   void SetText(string text);  
}  
interface IListBox: IControl  
{  
   void SetItems(string[] items);  
}  
interface IComboBox: ITextBox, IListBox {}  
the interface IComboBox inherits from both ITextBox and IListBox.
Classes and structs can implement multiple interfaces. In the example
interface IDataBound  
{  
   void Bind(Binder b);  
}  
public class EditBox: Control, IControl, IDataBound  
{  
   public void Paint() {...}  
   public void Bind(Binder b) {...}  
}   
the class EditBox derives from the class Control and implements both IControl and IDataBound.
In the previous example, the Paint method from the IControl interface and the Bind method from IDataBound interface are implemented using public members on the EditBox class. C# provides an alternative way of implementing these methods that allows the implementing class to avoid having these members be public. Interface members can be implemented using a qualified name. For example, the EditBox class could instead be implemented by providing IControl.Paint and IDataBound.Bind methods.
public class EditBox: IControl, IDataBound  
{  
   void IControl.Paint() {...}  
   void IDataBound.Bind(Binder b) {...}  
}  
Interface members implemented in this way are called explicit interface members because each member explicitly designates the interface member being implemented. Explicit interface members can only be called via the interface. For example, the EditBox's implementation of the Paint method can be called only by casting to the IControl interface.
class Test  
{  
   static void Main() {  
      EditBox editbox = new EditBox();  
      editbox.Paint();  // error: no such method  
      IControl control = editbox;  
      control.Paint();  // calls EditBox's Paint implementation  
   }  
}  



8.10 DelegatesDelegates enable scenarios that some other languages have addressed with function pointers. However, unlike function pointers, delegates are object-oriented and type-safe. A delegate declaration defines a class that is derived from the class System.Delegate. A delegate instance encapsulates one or more methods, each of which is referred to as a callable entity. For instance methods, a callable entity consists of an instance and a method on that instance. For static methods, a callable entity consists of just a method. Given a delegate instance and an appropriate set of arguments, one can invoke all of that delegate instance's methods with that set of arguments. An interesting and useful property of a delegate instance is that it does not know or care about the classes of the methods it encapsulates; all that matters is that those methods be compatible (
§22.1) with the delegate's type. This makes delegates perfectly suited for "anonymous" invocation. This is a powerful capability. There are three steps in defining and using delegates: declaration, instantiation, and invocation. Delegates are declared using delegate declaration syntax. The example
delegate void SimpleDelegate();  
declares a delegate named SimpleDelegate that takes no arguments and returns no result.
The example
class Test  
{  
   static void F() {  
      System.Console.WriteLine("Test.F");  
   }  
   static void Main() {  
      SimpleDelegate d = new SimpleDelegate(F);  
      d();  
   }  
}  
creates a SimpleDelegate instance and then immediately calls it.
There is not much point in instantiating a delegate for a method and then immediately calling that method via the delegate, as it would be simpler to call the method directly. Delegates really show their usefulness when their anonymity is used. The example
void MultiCall(SimpleDelegate d, int count) {  
   for (int i = 0; i < count; i++) {  
      d();  
   }  
}  
shows a MultiCall method that repeatedly calls a SimpleDelegate. The MultiCall method doesn't know or care about the type of the target method for the SimpleDelegate, what accessibility that method has, or whether or not that method is static. All that matters is that the target method is compatible (§22.1) with SimpleDelegate.



8.11 EnumsAn enum type declaration defines a type name for a related group of symbolic constants. Enums are used for "multiple choice" scenarios, in which a runtime decision is made from a fixed number of choices that are known at compile-time. The example
enum Color   
{  
   Red,  
   Blue,  
   Green  
}  
class Shape  
{  
   public void Fill(Color color) {  
      switch(color) {  
         case Color.Red:  
         ...  
         break;  
         case Color.Blue:  
         ...  
         break;  
         case Color.Green:  
         ...  
         break;  
         default:  
         break;  
      }  
   }  
}  
shows a Color enum and a method that uses this enum. The signature of the Fill method makes it clear that the shape can be filled with one of the given colors.
The use of enums is superior to the use of integer constants-as is common in languages without enums-because the use of enums makes the code more readable and self-documenting. The self-documenting nature of the code also makes it possible for the development tool to assist with code writing and other "designer" activities. For example, the use of Color rather than int for a parameter type enables smart code editors to suggest Color values.



8.12 Namespaces and assembliesThe programs presented so far have stood on their own except for dependence on a few system-provided classes such as System.Console. It is far more common, however, for real-world applications to consist of several different pieces, each compiled separately. For example, a corporate application might depend on several different components, including some developed internally and some purchased from independent software vendors. Namespaces and assemblies enable this component-based system. Namespaces provide a logical organizational system. Namespaces are used both as an "internal" organization system for a program, and as an "external" organization system-a way of presenting program elements that are exposed to other programs. Assemblies are used for physical packaging and deployment. An assembly may contain types, the executable code used to implement these types, and references to other assemblies. To demonstrate the use of namespaces and assemblies, this section revisits the "hello, world" program presented earlier, and splits it into two pieces: a class library that provides messages and a console application that displays them. The class library will contain a single class named HelloMessage. The example
// HelloLibrary.cs  
namespace CSharp.Introduction  
{  
   public class HelloMessage  
   {  
      public string Message {  
         get {  
            return "hello, world";  
         }  
      }  
   }  
}  
shows the HelloMessage class in a namespace named CSharp.Introduction. The HelloMessage class provides a read-only property named Message. Namespaces can nest, and the declaration
namespace CSharp.Introduction  
{...}  
is shorthand for two levels of namespace nesting:
namespace CSharp  
{  
   namespace Introduction  
   {...}  
}   
The next step in the componentization of "hello, world" is to write a console application that uses the HelloMessage class. The fully qualified name for the class-CSharp.Introduction.HelloMessage-could be used, but this name is quite long and unwieldy. An easier way is to use a using namespace directive, which makes it possible to use all of the types in a namespace without qualification. The example
// HelloApp.cs  
using CSharp.Introduction;  
class HelloApp  
{  
   static void Main() {  
      HelloMessage m = new HelloMessage();  
      System.Console.WriteLine(m.Message);  
   }  
}  
shows a using namespace directive that refers to the CSharp.Introduction namespace. The occurrences of HelloMessage are shorthand for CSharp.Introduction.HelloMessage.
C# also enables the definition and use of aliases. A using alias directive defines an alias for a type. Such aliases can be useful in situation in which name collisions occur between two class libraries, or when a small number of types from a much larger namespace are being used. The example
using MessageSource = CSharp.Introduction.HelloMessage;  
shows a using alias directive that defines MessageSource as an alias for the HelloMessage class.
The code we have written can be compiled into a class library containing the class HelloMessage and an application containing the class HelloApp. The details of this compilation step might differ based on the compiler or tool being used. A command-line compiler might enable compilation of a class library and an application that uses that library with the following command-line invocations:
csc /target:library HelloLibrary.cs   
csc /reference:HelloLibrary.dll HelloApp.cs  
which produce a class library named HelloLibrary.dll and an application named HelloApp.exe.



8.13 VersioningVersioning is the process of evolving a component over time in a compatible manner. A new version of a component is source compatible with a previous version if code that depends on the previous version can, when recompiled, work with the new version. In contrast, a new version of a component is binary compatible if an application that depended on the old version can, without recompilation, work with the new version. Most languages do not support binary compatibility at all, and many do little to facilitate source compatibility. In fact, some languages contain flaws that make it impossible, in general, to evolve a class over time without breaking at least some client code. As an example, consider the situation of a base class author who ships a class named Base. In the first version, Base contains no method F. A component named Derived derives from Base, and introduces an F. This Derived class, along with the class Base on which it depends, is released to customers, who deploy to numerous clients and servers.
// Author A  
namespace A   
{  
   public class Base   // version 1  
   {  
   }  
}  
// Author B  
namespace B  
{  
   class Derived: A.Base  
   {  
      public virtual void F() {  
         System.Console.WriteLine("Derived.F");   
      }  
   }  
}  
So far, so good, but now the versioning trouble begins. The author of Base produces a new version, giving it its own method F.
// Author A  
namespace A   
{  
   public class Base   // version 2  
   {  
      public virtual void F() {    // added in version 2  
         System.Console.WriteLine("Base.F");   
      }  
   }  
}  
This new version of Base should be both source and binary compatible with the initial version. (If it weren't possible to simply add a method then a base class could never evolve.) Unfortunately, the new F in Base makes the meaning of Derived's F unclear. Did Derived mean to override Base's F? This seems unlikely, since when Derived was compiled, Base did not even have an F! Further, if Derived's F does override Base's F, then it must adhere to the contract specified by Base-a contract that was unspecified when Derived was written. In some cases, this is impossible. For example, Base's F might require that overrides of it always call the base. Derived's F could not possibly adhere to such a contract. C# addresses this versioning problem by requiring developers to state their intent clearly. In the original code example, the code was clear, since Base did not even have an F. Clearly, Derived's F is intended as a new method rather than an override of a base method, since no base method named F exists. If Base adds an F and ships a new version, then the intent of a binary version of Derived is still clear-Derived's F is semantically unrelated, and should not be treated as an override. However, when Derived is recompiled, the meaning is unclear-the author of Derived may intend its F to override Base's F, or to hide it. Since the intent is unclear, the compiler produces a warning, and by default makes Derived's F hide Base's F. This course of action duplicates the semantics for the case in which Derived is not recompiled. The warning that is generated alerts Derived's author to the presence of the F method in Base. If Derived's F is semantically unrelated to Base's F, then Derived's author can express this intent-and, in effect, turn off the warning-by using the new keyword in the declaration of F.
// Author A  
namespace A   
{  
   public class Base   // version 2  
   {  
      public virtual void F() { // added in version 2  
         System.Console.WriteLine("Base.F");   
      }  
   }  
}  
// Author B  
namespace B  
{  
   class Derived: A.Base  // version 2a: new  
   {  
      new public virtual void F() {  
         System.Console.WriteLine("Derived.F");   
      }  
   }  
}  
On the other hand, Derived's author might investigate further, and decide that Derived's F should override Base's F. This intent can be specified by using the override keyword, as shown below.
// Author A  
namespace A   
{  
   public class Base     // version 2  
   {  
      public virtual void F() { // added in version 2  
         System.Console.WriteLine("Base.F");   
      }  
   }  
}  
// Author B  
namespace B  
{  
   class Derived: A.Base  // version 2b: override  
   {  
      public override void F() {  
         base.F();  
         System.Console.WriteLine("Derived.F");   
      }  
   }  
}  
The author of Derived has one other option, and that is to change the name of F, thus completely avoiding the name collision. Although this change would break source and binary compatibility for Derived, the importance of this compatibility varies depending on the scenario. If Derived is not exposed to other programs, then changing the name of F is likely a good idea, as it would improve the readability of the program-there would no longer be any confusion about the meaning of F.



8.14 AttributesC# is an imperative language, but like all imperative languages it does have some declarative elements. For example, the accessibility of a method in a class is specified by declaring it public, protected, internal, protected internal, or private. C# generalizes this capability, so that programmers can invent new kinds of declarative information, attach this declarative information to various program entities, and retrieve this declarative information at run-time. Programs specify this additional declarative information by defining and using attributes (
§24). For instance, a framework might define a HelpAttribute attribute that can be placed on program elements such as classes and methods, enabling developers to provide a mapping from program elements to documentation for them. The example
using System;  
[AttributeUsage(AttributeTargets.All)]  
public class HelpAttribute: Attribute  
{  
   public HelpAttribute(string url) {  
      this.url = url;  
   }  
   public string Topic = null;  
   private string url;  
   public string Url {   
      get { return url; }  
   }  
}  
defines an attribute class named HelpAttribute, or Help for short, that has one positional parameter (string url) and one named parameter (string Topic). Positional parameters are defined by the formal parameters for public instance constructors of the attribute class, and named parameters are defined by public non-static read-write fields and properties of the attribute class.
The example
[Help("http://www.mycompany.com/.../Class1.htm")]  
public class Class1   
{  
   [Help("http://www.mycompany.com/.../Class1.htm", Topic = "F")]  
   public void F() {}  
}  
shows several uses of the attribute Help.
Attribute information for a given program element can be retrieved at run-time by using reflection support. The example
using System;  
class Test  
{  
   static void Main() {  
      Type type = typeof(Class1);  
      object[] arr = type.GetCustomAttributes(typeof(HelpAttribute),  
      true);  
      if (arr.Length == 0)  
      Console.WriteLine("Class1 has no Help attribute.");  
      else {  
         HelpAttribute ha = (HelpAttribute) arr[0];  
         Console.WriteLine("Url = {0}, Topic = {1}", ha.Url, ha.Topic);  
      }  
   }  
}  
checks to see if Class1 has a Help attribute, and writes out the associated Topic and Url values if the attribute is present.
End of informative text.


9 Lexical structure



9.1 Programs Paragraph 11
A C# program consists of one or more source files, known formally as compilation units (§16.1). 2 A source file is an ordered sequence of Unicode characters. 3 Source files typically have a one-to-one correspondence with files in a file system, but this correspondence is not required. Paragraph 21 Conceptually speaking, a program is compiled using three steps: 2 1 Transformation, which converts a file from a particular character repertoire and encoding scheme into a sequence of Unicode characters. 3 2 Lexical analysis, which translates a stream of Unicode input characters into a stream of tokens. 4 3 Syntactic analysis, which translates the stream of tokens into executable code. Paragraph 31 Conforming implementations must accept Unicode source files encoded with the UTF-8 encoding form (as defined by the Unicode standard), and transform them into a sequence of Unicode characters. 2 Implementations may choose to accept and transform additional character encoding schemes (such as UTF-16, UTF-32, or non-Unicode character mappings). [Note: It is beyond the scope of this standard to define how a file using a character representation other than Unicode might be transformed into a sequence of Unicode characters. During such transformation, however, it is recommended that the usual line-separating character (or sequence) in the other character set be translated to the two-character sequence consisting of the Unicode carriage-return character followed by Unicode line-feed character. For the most part this transformation will have no visible effects; however, it will affect the interpretation of verbatim string literal tokens (§9.4.4.5). The purpose of this recommendation is to allow a verbatim string literal to produce the same character sequence when its source file is moved between systems that support differing non-Unicode character sets, in particular, those using differing character sequences for line-separation. end note]


9.2 Grammars Paragraph 11
This specification presents the syntax of the C# programming language using two grammars. 2 The lexical grammar (§9.2.1) defines how Unicode characters are combined to form line terminators, white space, comments, tokens, and pre-processing directives. 3 The syntactic grammar (§9.2.2) defines how the tokens resulting from the lexical grammar are combined to form C# programs.


9.2.1 Lexical grammar Paragraph 11
The lexical grammar of C# is presented in §9.3, §9.4, and §9.5. 2 The terminal symbols of the lexical grammar are the characters of the Unicode character set, and the lexical grammar specifies how characters are combined to form tokens (§9.4), white space (§9.3.3), comments (§9.3.2), and pre-processing directives (§9.5). Paragraph 21 Every source file in a C# program must conform to the input production of the lexical grammar (§9.3).


9.2.2 Syntactic grammar Paragraph 11
The syntactic grammar of C# is presented in the chapters and appendices that follow this chapter. 2 The terminal symbols of the syntactic grammar are the tokens defined by the lexical grammar, and the syntactic grammar specifies how tokens are combined to form C# programs. Paragraph 21 Every source file in a C# program must conform to the compilation-unit production (§16.1) of the syntactic grammar.


9.3 Lexical analysis Paragraph 11
The input production defines the lexical structure of a C# source file. 2 Each source file in a C# program must conform to this lexical grammar production. input :: input-sectionopt input-section :: input-section-part input-section input-section-part input-section-part :: input-elementsopt new-line pp-directive input-elements :: input-element input-elements input-element input-element :: whitespace comment token Paragraph 21 Five basic elements make up the lexical structure of a C# source file: Line terminators (§9.3.1), white space (§9.3.3), comments (§9.3.2), tokens (§9.4), and pre-processing directives (§9.5). 2 Of these basic elements, only tokens are significant in the syntactic grammar of a C# program (§9.2.2). Paragraph 31 The lexical processing of a C# source file consists of reducing the file into a sequence of tokens which becomes the input to the syntactic analysis. 2 Line terminators, white space, and comments can serve to separate tokens, and pre-processing directives can cause sections of the source file to be skipped, but otherwise these lexical elements have no impact on the syntactic structure of a C# program. Paragraph 41 When several lexical grammar productions match a sequence of characters in a source file, the lexical processing always forms the longest possible lexical element. [Example: For example, the character sequence // is processed as the beginning of a single-line comment because that lexical element is longer than a single / token. end example]


9.3.1 Line terminators Paragraph 11
Line terminators divide the characters of a C# source file into lines. new-line :: Carriage return character (U+000D) Line feed character (U+000A) Carriage return character (U+000D) followed by line feed character (U+000A) Line separator character (U+2028) Paragraph separator character (U+2029) Paragraph 21 For compatibility with source code editing tools that add end-of-file markers, and to enable a source file to be viewed as a sequence of properly terminated lines, the following transformations are applied, in order, to every source file in a C# program:


9.3.2 Comments Paragraph 11
Two forms of comments are supported: delimited comments and single-line comments. Paragraph 21 A delimited comment begins with the characters /* and ends with the characters */. 2 Delimited comments can occupy a portion of a line, a single line, or multiple lines. [Example: The example
/* Hello, world program  
This program writes "hello, world" to the console  
*/  
class Hello  
{  
   static void Main() {  
      System.Console.WriteLine("hello, world");  
   }  
}  
includes a delimited comment. end example]
Paragraph 31 A single-line comment begins with the characters // and extends to the end of the line. [Example: The example
// Hello, world program  
//   This program writes "hello, world" to the console  
//  
class Hello // any name will do for this class  
{  
   static void Main() { // this method must be named "Main"  
      System.Console.WriteLine("hello, world");  
   }  
}  
shows several single-line comments. end example]
comment :: single-line-comment delimited-comment single-line-comment :: // input-charactersopt input-characters :: input-character input-characters input-character input-character :: Any Unicode character except a new-line-character new-line-character :: Carriage return character (U+000D) Line feed character (U+000A) Line separator character (U+2028) Paragraph separator character (U+2029) delimited-comment :: /* delimited-comment-charactersopt */ delimited-comment-characters :: delimited-comment-character delimited-comment-characters delimited-comment-character delimited-comment-character :: not-asterisk * not-slash not-asterisk :: Any Unicode character except * not-slash :: Any Unicode character except /
Paragraph 41 Comments do not nest. 2 The character sequences /* and */ have no special meaning within a single-line comment, and the character sequences // and /* have no special meaning within a delimited comment. Paragraph 51 Comments are not processed within character and string literals.


9.3.3 White space Paragraph 11
White space is defined as any character with Unicode class Zs (which includes the space character) as well as the horizontal tab character, the vertical tab character, and the form feed character. whitespace :: Any character with Unicode class Zs Horizontal tab character (U+0009) Vertical tab character (U+000B) Form feed character (U+000C)


9.4 Tokens Paragraph 11
There are several kinds of tokens: identifiers, keywords, literals, operators, and punctuators. 2 White space and comments are not tokens, though they act as separators for tokens. token :: identifier keyword integer-literal real-literal character-literal string-literal operator-or-punctuator


9.4.1 Unicode escape sequences Paragraph 11
A Unicode escape sequence represents a Unicode character. 2 Unicode escape sequences are processed in identifiers (§9.4.2), regular string literals (§9.4.4.5), and character literals (§9.4.4.4). 3 A Unicode character escape is not processed in any other location (for example, to form an operator, punctuator, or keyword). unicode-escape-sequence :: \u hex-digit hex-digit hex-digit hex-digit \U hex-digit hex-digit hex-digit hex-digit hex-digit hex-digit hex-digit hex-digit Paragraph 21 A Unicode escape sequence represents the single Unicode character formed by the hexadecimal number following the "\u" or "\U" characters. 2 Since C# uses a 16-bit encoding of Unicode characters in characters and string values, a Unicode character in the range U+10000 to U+10FFFF is represented using two Unicode surrogate characters. 3 Unicode characters with code points above 0x10FFFF are not supported. Paragraph 31 Multiple translations are not performed. 2 For instance, the string literal "\u005Cu005C" is equivalent to "\u005C" rather than "\". [Note: The Unicode value \u005C is the character "\". end note] [Example: The example
class Class1  
{  
   static void Test(bool \u0066) {  
      char c = '\u0066';  
      if (\u0066)  
      System.Console.WriteLine(c.ToString());  
   }     
}  
shows several uses of \u0066, which is the escape sequence for the letter "f". The program is equivalent to
class Class1  
{  
   static void Test(bool f) {  
      char c = 'f';  
      if (f)  
      System.Console.WriteLine(c.ToString());  
   }     
}  
end example]



9.4.2 Identifiers Paragraph 11
The rules for identifiers given in this section correspond exactly to those recommended by the Unicode Standard Annex 15 except that underscore is allowed as an initial character (as is traditional in the C programming language), Unicode escape sequences are permitted in identifiers, and the "@" character is allowed as a prefix to enable keywords to be used as identifiers. identifier :: available-identifier @ identifier-or-keyword available-identifier :: An identifier-or-keyword that is not a keyword identifier-or-keyword :: identifier-start-character identifier-part-charactersopt identifier-start-character :: letter-character _ (the underscore character U+005F) identifier-part-characters :: identifier-part-character identifier-part-characters identifier-part-character identifier-part-character :: letter-character decimal-digit-character connecting-character combining-character formatting-character letter-character :: A Unicode character of classes Lu, Ll, Lt, Lm, Lo, or Nl A unicode-escape-sequence representing a character of classes Lu, Ll, Lt, Lm, Lo, or Nl combining-character :: A Unicode character of classes Mn or Mc A unicode-escape-sequence representing a character of classes Mn or Mc decimal-digit-character :: A Unicode character of the class Nd A unicode-escape-sequence representing a character of the class Nd connecting-character :: A Unicode character of the class Pc A unicode-escape-sequence representing a character of the class Pc formatting-character :: A Unicode character of the class Cf A unicode-escape-sequence representing a character of the class Cf [Note: For information on the Unicode character classes mentioned above, see The Unicode Standard, Verson 3.0, 4-5. end note] [Example: Examples of valid identifiers include "identifier1", "_identifier2", and "@if". end example] Paragraph 21 An identifier in a conforming program must be in the canonical format defined by Unicode Normalization Form C, as defined by Unicode Standard Annex 15. 2 The behavior when encountering an identifier not in Normalization Form C is implementation-defined; however, a diagnostic is not required. Paragraph 31 The prefix "@" enables the use of keywords as identifiers, which is useful when interfacing with other programming languages. 2 The character @ is not actually part of the identifier, so the identifier might be seen in other languages as a normal identifier, without the prefix. 3 An identifier with an @ prefix is called a verbatim identifier. [Note: Use of the @ prefix for identifiers that are not keywords is permitted, but strongly discouraged as a matter of style. end note] [Example: The example:
class @class  
{  
   public static void @static(bool @bool) {  
      if (@bool)  
      System.Console.WriteLine("true");  
      else  
      System.Console.WriteLine("false");  
   }    
}  
class Class1  
{  
   static void M() {  
      cl\u0061ss.st\u0061tic(true);  
   }  
}  
defines a class named "class" with a static method named "static" that takes a parameter named "bool". Note that since Unicode escapes are not permitted in keywords, the token "cl\u0061ss" is an identifier, and is the same identifier as "@class". end example]
Paragraph 41 Two identifiers are considered the same if they are identical after the following transformations are applied, in order: Paragraph 51 Identifiers containing two consecutive underscore characters (U+005F) are reserved for use by the implementation; however, no diagnostic is required if such an identifier is defined. [Note: For example, an implementation might provide extended keywords that begin with two underscores. end note]


9.4.3 Keywords Paragraph 11
A keyword is an identifier-like sequence of characters that is reserved, and cannot be used as an identifier except when prefaced by the @ character. keyword :: one of abstract as base bool break byte case catch char checked class const continue decimal default delegate do double else enum event explicit extern false finally fixed float for foreach goto if implicit in int interface internal is lock long namespace new null object operator out override params private protected public readonly ref return sbyte sealed short sizeof stackalloc static string struct switch this throw true try typeof uint ulong unchecked unsafe ushort using virtual void volatile while Paragraph 21 In some places in the grammar, specific identifiers have special meaning, but are not keywords. [Note: For example, within a property declaration, the "get" and "set" identifiers have special meaning (§17.6.2). An identifier other than get or set is never permitted in these locations, so this use does not conflict with a use of these words as identifiers. end note]


9.4.4 Literals Paragraph 11
A literal is a source code representation of a value. literal :: boolean-literal integer-literal real-literal character-literal string-literal null-literal


9.4.4.1 Boolean literals Paragraph 11
There are two boolean literal values: true and false. boolean-literal :: true false Paragraph 21 The type of a boolean-literal is bool.


9.4.4.2 Integer literals Paragraph 11
Integer literals are used to write values of types int, uint, long, and ulong. 2 Integer literals have two possible forms: decimal and hexadecimal. integer-literal :: decimal-integer-literal hexadecimal-integer-literal decimal-integer-literal :: decimal-digits integer-type-suffixopt decimal-digits :: decimal-digit decimal-digits decimal-digit decimal-digit :: one of 0 1 2 3 4 5 6 7 8 9 integer-type-suffix :: one of U u L l UL Ul uL ul LU Lu lU lu hexadecimal-integer-literal :: 0x hex-digits integer-type-suffixopt 0X hex-digits integer-type-suffixopt hex-digits :: hex-digit hex-digits hex-digit hex-digit :: one of 0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f Paragraph 21 The type of an integer literal is determined as follows: Paragraph 31 If the value represented by an integer literal is outside the range of the ulong type, a compile-time error occurs. [Note: As a matter of style, it is suggested that "L" be used instead of "l" when writing literals of type long, since it is easy to confuse the letter "l" with the digit "1". end note] Paragraph 41 To permit the smallest possible int and long values to be written as decimal integer literals, the following two rules exist:


9.4.4.3 Real literals Paragraph 11
Real literals are used to write values of types float, double, and decimal. real-literal :: decimal-digits . decimal-digits exponent-partopt real-type-suffixopt . decimal-digits exponent-partopt real-type-suffixopt decimal-digits exponent-part real-type-suffixopt decimal-digits real-type-suffix exponent-part :: e signopt decimal-digits E signopt decimal-digits sign :: one of + - real-type-suffix :: one of F f D d M m Paragraph 21 If no real-type-suffix is specified, the type of the real literal is double. 2 Otherwise, the real-type-suffix determines the type of the real literal, as follows: Paragraph 31 If the specified literal cannot be represented in the indicated type, a compile-time error occurs. Paragraph 41 The value of a real literal having type float or double is determined by using the IEEE "round to nearest" mode.


9.4.4.4 Character literals Paragraph 11
A character literal represents a single character, and usually consists of a character in quotes, as in 'a'. character-literal :: ' character ' character :: single-character simple-escape-sequence hexadecimal-escape-sequence unicode-escape-sequence single-character :: Any character except ' (U+0027), \ (U+005C), and new-line-character simple-escape-sequence :: one of \' \" \\ \0 \a \b \f \n \r \t \v hexadecimal-escape-sequence :: \x hex-digit hex-digitopt hex-digitopt hex-digitopt [Note: A character that follows a backslash character (\) in a character must be one of the following characters: ', ", \, 0, a, b, f, n, r, t, u, U, x, v. Otherwise, a compile-time error occurs. end note] Paragraph 21 A hexadecimal escape sequence represents a single Unicode character, with the value formed by the hexadecimal number following "\x". Paragraph 31 If the value represented by a character literal is greater than U+FFFF, a compile-time error occurs. Paragraph 41 A Unicode character escape sequence (§9.4.1) in a character literal must be in the range U+0000 to U+FFFF. Paragraph 51 A simple escape sequence represents a Unicode character encoding, as described in the table below.
Escape
Sequence
Character
name
Unicode
encoding
\' Single quote 0x0027
\" Double quote 0x0022
\\ Backslash 0x005C
\0 Null 0x0000
\a Alert 0x0007
\b Backspace 0x0008
\f Form feed 0x000C
\n New line 0x000A
\r Carriage return 0x000D
\t Horiizontal tab 0x0009
\v Vertical quote 0x000B
Paragraph 61 The type of a character-literal is char.


9.4.4.5 String literals1
C# supports two forms of string literals: regular string literals and verbatim string literals. 2 A regular string literal consists of zero or more characters enclosed in double quotes, as in "hello, world", and may include both simple escape sequences (such as \t for the tab character), and hexadecimal and Unicode escape sequences. Paragraph 11 A verbatim string literal consists of an @ character followed by a double-quote character, zero or more 2 characters, and a closing double-quote character. [Example: A simple example is @"hello, world". end example] 3 In a verbatim string literal, the characters between the delimiters are interpreted verbatim, with the only exception being a quote-escape-sequence. 4 In particular, simple escape sequences, and hexadecimal and Unicode escape sequences are not processed in verbatim string literals. 5 A verbatim string literal may span multiple lines. string-literal :: regular-string-literal verbatim-string-literal regular-string-literal :: " regular-string-literal-charactersopt " regular-string-literal-characters :: regular-string-literal-character regular-string-literal-characters regular-string-literal-character regular-string-literal-character :: single-regular-string-literal-character simple-escape-sequence hexadecimal-escape-sequence unicode-escape-sequence single-regular-string-literal-character :: Any character except " (U+0022), \ (U+005C), and new-line-character verbatim-string-literal :: @" verbatim-string-literal-charactersopt " verbatim-string-literal-characters :: verbatim-string-literal-character verbatim-string-literal-characters verbatim-string-literal-character verbatim-string-literal-character :: single-verbatim-string-literal-character quote-escape-sequence single-verbatim-string-literal-character :: Any character except " quote-escape-sequence :: "" [Note: A character that follows a backslash character (\) in a regular-string-literal-character must be one of the following characters: ', ", \, 0, a, b, f, n, r, t, u, U, x, v. Otherwise, a compile-time error occurs. end note] [Example: The example
string a = "Happy birthday, Joel";      // Happy birthday, Joel  
string b = @"Happy birthday, Joel";     // Happy birthday, Joel  
string c = "hello \t world";          // hello    world  
string d = @"hello \t world";         // hello \t world  
string e = "Joe said \"Hello\" to me";   // Joe said "Hello" to me  
string f = @"Joe said ""Hello"" to me";  // Joe said "Hello" to me  
string g = "\\\\server\\share\\file.txt"; // \\server\share\file.txt  
string h = @"\\server\share\file.txt";   // \\server\share\file.txt  
string i = "one\r\ntwo\r\nthree";  
string j = @"one  
two  
three";  
shows a variety of string literals. The last string literal, j, is a verbatim string literal that spans multiple lines. The characters between the quotation marks, including white space such as new line characters, are preserved verbatim. end example]
[Note: Since a hexadecimal escape sequence can have a variable number of hex digits, the string literal "\x123" contains a single character with hex value 123. To create a string containing the character with hex value 12 followed by the character 3, one could write "\x00123" or "\x12" + "3" instead. end note] Paragraph 21 The type of a string-literal is string. Paragraph 31 Each string literal does not necessarily result in a new string instance. 2 When two or more string literals that are equivalent according to the string equality operator (§14.9.7), appear in the same assembly, these string literals refer to the same string instance. [Example: For instance, the output produced by
class Test  
{  
   static void Main() {  
      object a = "hello";  
      object b = "hello";  
      System.Console.WriteLine(a == b);  
   }  
}  
is True because the two literals refer to the same string instance. end example]



9.4.4.6 The null literal
null-literal :: null Paragraph 11 The type of a null-literal is the null type.


9.4.5 Operators and punctuators Paragraph 11
There are several kinds of operators and punctuators. 2 Operators are used in expressions to describe operations involving one or more operands. [Example: For example, the expression a + b uses the + operator to add the two operands a and b. end example] 3 Punctuators are for grouping and separating. operator-or-punctuator :: one of { } [ ] ( ) . , : ; + - * / % & | ^ ! ~ = < > ? ++ -- && || << >> == != <= >= += -= *= /= %= &= |= ^= <<= >>= ->


9.5 Pre-processing directives Paragraph 11
The pre-processing directives provide the ability to conditionally skip sections of source files, to report error and warning conditions, and to delineate distinct regions of source code. [Note: The term "pre-processing directives" is used only for consistency with the C and C++ programming languages. In C#, there is no separate pre-processing step; pre-processing directives are processed as part of the lexical analysis phase. end note] pp-directive :: pp-declaration pp-conditional pp-line pp-diagnostic pp-region Paragraph 21 The following pre-processing directives are available: Paragraph 31 A pre-processing directive always occupies a separate line of source code and always begins with a # character and a pre-processing directive name. 2 White space may occur before the # character and between the # character and the directive name. Paragraph 41 A source line containing a #define, #undef, #if, #elif, #else, #endif, or #line directive may end with a single-line comment. 2 Delimited comments (the /* */ style of comments) are not permitted on source lines containing pre-processing directives. Paragraph 51 Pre-processing directives are not tokens and are not part of the syntactic grammar of C#. 2 However, pre-processing directives can be used to include or exclude sequences of tokens and can in that way affect the meaning of a C# program. [Example: For example, when compiled, the program
#define A  
#undef B  
class C  
{  
   #if A  
   void F() {}  
   #else  
   void G() {}  
   #endif  
   #if B  
   void H() {}  
   #else  
   void I() {}  
   #endif  
}  
results in the exact same sequence of tokens as the program
class C  
{  
   void F() {}  
   void I() {}  
}  
Thus, whereas lexically, the two programs are quite different, syntactically, they are identical. end example]


9.5.1 Conditional compilation symbols Paragraph 11
The conditional compilation functionality provided by the #if, #elif, #else, and #endif directives is controlled through pre-processing expressions (§9.5.2) and conditional compilation symbols. conditional-symbol :: Any identifier-or-keyword except true or false Paragraph 21 A conditional compilation symbol has two possible states: defined or undefined. 2 At the beginning of the lexical processing of a source file, a conditional compilation symbol is undefined unless it has been explicitly defined by an external mechanism (such as a command-line compiler option). 3 When a #define directive is processed, the conditional compilation symbol named in that directive becomes defined in that source file. 4 The symbol remains defined until an #undef directive for that same symbol is processed, or until the end of the source file is reached. 5 An implication of this is that #define and #undef directives in one source file have no effect on other source files in the same program. Paragraph 31 The name space for conditional compilation symbols is distinct and separate from all other named entities in a C# program. 2 Conditional compilation symbols can only be referenced in #define and #undef directives and in pre-processing expressions.


9.5.2 Pre-processing expressions Paragraph 11
Pre-processing expressions can occur in #if and #elif directives. 2 The operators !, ==, !=, && and || are permitted in pre-processing expressions, and parentheses may be used for grouping. pp-expression :: whitespaceopt pp-or-expression whitespaceopt pp-or-expression :: pp-and-expression pp-or-expression whitespaceopt || whitespaceopt pp-and-expression pp-and-expression :: pp-equality-expression pp-and-expression whitespaceopt && whitespaceopt pp-equality-expression pp-equality-expression :: pp-unary-expression pp-equality-expression whitespaceopt == whitespaceopt pp-unary-expression pp-equality-expression whitespaceopt != whitespaceopt pp-unary-expression pp-unary-expression :: pp-primary-expression ! whitespaceopt pp-unary-expression pp-primary-expression :: true false conditional-symbol ( whitespaceopt pp-expression whitespaceopt ) Paragraph 21 When referenced in a pre-processing expression, a defined conditional compilation symbol has the boolean value true, and an undefined conditional compilation symbol has the boolean value false. Paragraph 31 Evaluation of a pre-processing expression always yields a boolean value. 2 The rules of evaluation for a pre-processing expression are the same as those for a constant expression (§14.15), except that the only user-defined entities that can be referenced are conditional compilation symbols.


9.5.3 Declaration directives Paragraph 11
The declaration directives are used to define or undefine conditional compilation symbols. pp-declaration :: whitespaceopt # whitespaceopt define whitespace conditional-symbol pp-new-line whitespaceopt # whitespaceopt undef whitespace conditional-symbol pp-new-line pp-new-line :: whitespaceopt single-line-commentopt new-line Paragraph 21 The processing of a #define directive causes the given conditional compilation symbol to become defined, starting with the source line that follows the directive. 2 Likewise, the processing of an #undef directive causes the given conditional compilation symbol to become undefined, starting with the source line that follows the directive. Paragraph 31 Any #define and #undef directives in a source file must occur before the first token (§9.4) in the source file; otherwise a compile-time error occurs. 2 In intuitive terms, #define and #undef directives must precede any "real code" in the source file. [Example: The example:
#define Enterprise  
#if Professional || Enterprise  
#define Advanced  
#endif  
namespace Megacorp.Data  
{  
   #if Advanced  
   class PivotTable {...}  
   #endif  
}  
is valid because the #define directives precede the first token (the namespace keyword) in the source file. end example]
[Example: The following example results in a compile-time error because a #define follows real code:
#define A  
namespace N  
{  
   #define B  
   #if B  
   class Class1 {}  
   #endif  
}  
end example]
Paragraph 41 A #define may define a conditional compilation symbol that is already defined, without there being any intervening #undef for that symbol. [Example: The example below defines a conditional compilation symbol A and then defines it again.
#define A  
#define A  
For compilers that allow conditional compilation symbols to be defined as compilation options, an alternative way for such redefinition to occur is to define the symbol as a compiler option as well as in the source. end example] Paragraph 51 A #undef may "undefine" a conditional compilation symbol that is not defined. [Example: The example below defines a conditional compilation symbol A and then undefines it twice; although the second #undef has no effect, it is still valid.
#define A  
#undef A  
#undef A  
end example]



9.5.4 Conditional compilation directives Paragraph 11
The conditional compilation directives are used to conditionally include or exclude portions of a source file. pp-conditional :: pp-if-section pp-elif-sectionsopt pp-else-sectionopt pp-endif pp-if-section :: whitespaceopt # whitespaceopt if whitespace pp-expression pp-new-line conditional-sectionopt pp-elif-sections :: pp-elif-section pp-elif-sections pp-elif-section pp-elif-section :: whitespaceopt # whitespaceopt elif whitespace pp-expression pp-new-line conditional-sectionopt pp-else-section :: whitespaceopt # whitespaceopt else pp-new-line conditional-sectionopt pp-endif :: whitespaceopt # whitespaceopt endif pp-new-line conditional-section :: input-section skipped-section skipped-section :: skipped-section-part skipped-section skipped-section-part skipped-section-part :: skipped-charactersopt new-line pp-directive skipped-characters :: whitespaceopt not-number-sign input-charactersopt not-number-sign :: Any input-character except # [Note: As indicated by the syntax, conditional compilation directives must be written as sets consisting of, in order, an #if directive, zero or more #elif directives, zero or one #else directive, and an #endif directive. Between the directives are conditional sections of source code. Each section is controlled by the immediately preceding directive. A conditional section may itself contain nested conditional compilation directives provided these directives form complete sets. end note] Paragraph 21 A pp-conditional selects at most one of the contained conditional-sections for normal lexical processing: Paragraph 31 The selected conditional-section, if any, is processed as a normal input-section: the source code contained in the section must adhere to the lexical grammar; tokens are generated from the source code in the section; and pre-processing directives in the section have the prescribed effects. Paragraph 41 The remaining conditional-sections, if any, are processed as skipped-sections: except for pre-processing directives, the source code in the section need not adhere to the lexical grammar; no tokens are generated from the source code in the section; and pre-processing directives in the section must be lexically correct but are not otherwise processed. 2 Within a conditional-section that is being processed as a skipped-section, any nested conditional-sections (contained in nested #if...#endif and #region...#endregion constructs) are also processed as skipped-sections. [Example: The following example illustrates how conditional compilation directives can nest:
#define Debug    // Debugging on  
#undef Trace    // Tracing off  
class PurchaseTransaction  
{  
   void Commit() {  
      #if Debug  
      CheckConsistency();  
      #if Trace  
      WriteToLog(this.ToString());  
      #endif  
      #endif  
      CommitHelper();  
   }  
}  
Except for pre-processing directives, skipped source code is not subject to lexical analysis. For example, the following is valid despite the unterminated comment in the #else section:
#define Debug    // Debugging on  
class PurchaseTransaction  
{  
   void Commit() {  
      #if Debug  
      CheckConsistency();  
      #else  
      /* Do something else  
      #endif  
   }  
}  
Note, however, that pre-processing directives are required to be lexically correct even in skipped sections of source code. Pre-processing directives are not processed when they appear inside multi-line input elements. For example, the program:
class Hello  
{  
   static void Main() {  
      System.Console.WriteLine(@"hello,   
      #if Debug  
      world  
      #else  
      Nebraska  
      #endif  
      ");  
   }  
}  
results in the output:
hello,  
#if Debug  
world  
#else  
Nebraska  
#endif  
In peculiar cases, the set of pre-processing directives that is processed might depend on the evaluation of the pp-expression. The example:
#if X  
/*   
#else  
/* */ class Q { }  
#endif   
always produces the same token stream (class Q { }), regardless of whether or not X is defined. If X is defined, the only processed directives are #if and #endif, due to the multi-line comment. If X is undefined, then three directives (#if, #else, #endif) are part of the directive set. end example]



9.5.5 Diagnostic directives Paragraph 11
The diagnostic directives are used to explicitly generate error and warning messages that are reported in the same way as other compile-time errors and warnings. pp-diagnostic :: whitespaceopt # whitespaceopt error pp-message whitespaceopt # whitespaceopt warning pp-message pp-message :: new-line whitespace input-charactersopt new-line [Example: The example
#warning Code review needed before check-in  
#if Debug && Retail  
#error A build can't be both debug and retail  
#endif  
class Test {...}  
always produces a warning ("Code review needed before check-in"), and produces a compile-time error if the pre-processing identifiers Debug and Retail are both defined. Note that a pp-message can contain arbitrary text; specifically, it need not contain well-formed tokens, as shown by the single quote in the word can't. end example]



9.5.6 Region control Paragraph 11
The region directives are used to explicitly mark regions of source code. pp-region :: pp-start-region conditional-sectionopt pp-end-region pp-start-region :: whitespaceopt # whitespaceopt region pp-message pp-end-region :: whitespaceopt # whitespaceopt endregion pp-message Paragraph 21 No semantic meaning is attached to a region; regions are intended for use by the programmer or by automated tools to mark a section of source code. 2 The message specified in a #region or #endregion directive likewise has no semantic meaning; it merely serves to identify the region. 3 Matching #region and #endregion directives may have different pp-messages. Paragraph 31 The lexical processing of a region:
#region  
...  
#endregion  
corresponds exactly to the lexical processing of a conditional compilation directive of the form:
#if true  
...  
#endif  



9.5.7 Line directives Paragraph 11
Line directives may be used to alter the line numbers and source file names that are reported by the compiler in output such as warnings and errors. [Note: Line directives are most commonly used in meta-programming tools that generate C# source code from some other text input. end note] pp-line :: whitespaceopt # whitespaceopt line whitespace line-indicator pp-new-line line-indicator :: decimal-digits whitespace file-name decimal-digits default file-name :: " file-name-characters " file-name-characters :: file-name-character file-name-characters file-name-character file-name-character :: Any character except " (U+0022), and new-line Paragraph 21 When no #line directives are present, the compiler reports true line numbers and source file names in its output. 2 When processing a #line directive that includes a line-indicator that is not default, the compiler treats the line after the directive as having the given line number (and file name, if specified). Paragraph 31 A #line default directive reverses the effect of all preceding #line directives. 2 The compiler reports true line information for subsequent lines, precisely as if no #line directives had been processed. [Note: Note that a file-name differs from a regular string literal in that escape characters are not processed; the '\' character simply designates an ordinary back-slash character within a file-name. end note]


10 Basic concepts



10.1 Application startup Paragraph 11
Application startup occurs when the execution environment calls a designated method, which is referred to as the application's entry point. 2 This entry point method is always named Main, and shall have one of the following signatures:
static void Main() {...}  
static void Main(string[] args) {...}  
static int Main() {...}  
static int Main(string[] args) {...}  
Paragraph 21 As shown, the entry point may optionally return an int value. 2 This return value is used in application termination (§10.2). Paragraph 31 The entry point may optionally have one formal parameter, and this formal parameter may have any name. 2 If such a parameter is declared, it must obey the following constraints: Paragraph 41 Since C# supports method overloading, a class or struct may contain multiple definitions of some method, provided each has a different signature. 2 However, within a single program, no class or struct shall contain more than one method called Main whose definition qualifies it to be used as an application entry point. 3 Other overloaded versions of Main are permitted, however, provided they have more than one parameter, or their only parameter is other than type string[]. Paragraph 51 An application can be made up of multiple classes or structs. 2 It is possible for more than one of these classes or structs to contain a method called Main whose definition qualifies it to be used as an application entry point. 3 In such cases, one of these Main methods must be chosen as the entry point so that application startup can occur. 4 This choice of an entry point is beyond the scope of this specification-no mechanism for specifying or determining an entry point is provided. Paragraph 61 In C#, every method must be defined as a member of a class or struct. 2 Ordinarily, the declared accessibility (§10.5.1) of a method is determined by the access modifiers (§17.2.3) specified in its declaration, and similarly the declared accessibility of a type is determined by the access modifiers specified in its declaration. 3 In order for a given method of a given type to be callable, both the type and the member must be accessible. 4 However, the application entry point is a special case. 5 Specifically, the execution environment can access the application's entry point regardless of its declared accessibility and regardless of the declared accessibility of its enclosing type declarations. Paragraph 71 In all other respects, entry point methods behave like those that are not entry points.


10.2 Application termination Paragraph 11
Application termination returns control to the execution environment. Paragraph 21 If the return type of the application's entry point method is int, the value returned serves as the application's termination status code. 2 The purpose of this code is to allow communication of success or failure to the execution environment. Paragraph 31 If the return type of the entry point method is void, reaching the right brace (}) which terminates that method, or executing a return statement that has no expression, results in a termination status code of 0. Paragraph 41 Prior to an application's termination, destructors for all of its objects that have not yet been garbage collected are called, unless such cleanup has been suppressed (by a call to the library method GC.SuppressFinalize, for example).


10.3 Declarations Paragraph 11
Declarations in a C# program define the constituent elements of the program. 2 C# programs are organized using namespaces (§16), which can contain type declarations and nested namespace declarations. 3 Type declarations (§16.5) are used to define classes (§17), structs (§18), interfaces (§20), enums (§21), and delegates (§22). 4 The kinds of members permitted in a type declaration depend on the form of the type declaration. 5 For instance, class declarations can contain declarations for constants (§17.3), fields (§17.4), methods (§17.5), properties (§17.6), events (§17.7), indexers (§17.8), operators (§17.9), instance constructors (§17.10), destructors (§17.12), static constructors (§17.11), and nested types. Paragraph 21 A declaration defines a name in the declaration space to which the declaration belongs. 2 Except for overloaded members (§10.6), it is a compile-time error to have two or more declarations that introduce members with the same name in a declaration space. 3 However, no diagnostic is required if the declaration space is a namespace for the global declaration space and the conflicting declarations are in separate programs. 4 It is never possible for a declaration space to contain different kinds of members with the same name. [Example: For example, a declaration space can never contain a field and a method by the same name. end example] Paragraph 31 There are several different types of declaration spaces, as described in the following. Paragraph 41 The textual order in which names are declared is generally of no significance. 2 In particular, textual order is not significant for the declaration and use of namespaces, constants, methods, properties, events, indexers, operators, instance constructors, destructors, static constructors, and types. 3 Declaration order is significant in the following ways: [Example: The declaration space of a namespace is "open ended", and two namespace declarations with the same fully qualified name contribute to the same declaration space. For example
namespace Megacorp.Data  
{  
   class Customer  
   {  
      ...  
   }  
}  
namespace Megacorp.Data  
{  
   class Order  
   {  
      ...  
   }  
}  
The two namespace declarations above contribute to the same declaration space, in this case declaring two classes with the fully qualified names Megacorp.Data.Customer and Megacorp.Data.Order. Because the two declarations contribute to the same declaration space, it would have caused a compile-time error if each contained a declaration of a class with the same name. end example] [Note: As specified above, the declaration space of a block includes any nested blocks. Thus, in the following example, the F and G methods result in a compile-time error because the name i is declared in the outer block and cannot be redeclared in the inner block. However, the H and I methods are valid since the two i's are declared in separate non-nested blocks.
class A  
{  
   void F() {  
      int i = 0;  
      if (true) {  
         int i = 1;        
      }  
   }  
   void G() {  
      if (true) {  
         int i = 0;  
      }  
      int i = 1;          
   }  
   void H() {  
      if (true) {  
         int i = 0;  
      }  
      if (true) {  
         int i = 1;  
      }  
   }  
   void I() {  
      for (int i = 0; i < 10; i++)  
      H();  
      for (int i = 0; i < 10; i++)  
      H();  
   }  
}  
end note]



10.4 Members Paragraph 11
Namespaces and types have members. [Note: The members of an entity are generally available through the use of a qualified name that starts with a reference to the entity, followed by a "." token, followed by the name of the member. end note] Paragraph 21 Members of a type are either declared in the type or inherited from the base class of the type. 2 When a type inherits from a base class, all members of the base class, except instance constructors, destructors, and static constructors become members of the derived type. 3 The declared accessibility of a base class member does not control whether the member is inherited-inheritance extends to any member that isn't an instance constructor, static constructor, or destructor. 4 However, an inherited member may not be accessible in a derived type, either because of its declared accessibility (§10.5.1) or because it is hidden by a declaration in the type itself (§10.7.1.2).


10.4.1 Namespace members Paragraph 11
Namespaces and types that have no enclosing namespace are members of the global namespace. 2 This corresponds directly to the names declared in the global declaration space. Paragraph 21 Namespaces and types declared within a namespace are members of that namespace. 2 This corresponds directly to the names declared in the declaration space of the namespace. Paragraph 31 Namespaces have no access restrictions. 2 It is not possible to declare private, protected, or internal namespaces, and namespace names are always publicly accessible.


10.4.2 Struct members Paragraph 11
The members of a struct are the members declared in the struct and the members inherited from the struct's direct base class System.ValueType and the indirect base class object. Paragraph 21 The members of a simple type correspond directly to the members of the struct type aliased by the simple type:


10.4.3 Enumeration members Paragraph 11
The members of an enumeration are the constants declared in the enumeration and the members inherited from class object.


10.4.4 Class members Paragraph 11
The members of a class are the members declared in the class and the members inherited from the base class (except for class object which has no base class). 2 The members inherited from the base class include the constants, fields, methods, properties, events, indexers, operators, and types of the base class, but not the instance constructors, destructors, and static constructors of the base class. 3 Base class members are inherited without regard to their accessibility. Paragraph 21 A class declaration may contain declarations of constants, fields, methods, properties, events, indexers, operators, instance constructors, destructors, static constructors, and types. Paragraph 31 The members of object and string correspond directly to the members of the class types they alias:


10.4.5 Interface members Paragraph 11
The members of an interface are the members declared in the interface and in all base interfaces of the interface, and the members inherited from class object.


10.4.6 Array members Paragraph 11
The members of an array are the members inherited from class System.Array.


10.4.7 Delegate members Paragraph 11
The members of a delegate are the members inherited from class System.Delegate.


10.5 Member access Paragraph 11
Declarations of members allow control over member access. 2 The accessibility of a member is established by the declared accessibility (§10.5.1) of the member combined with the accessibility of the immediately containing type, if any. Paragraph 21 When access to a particular member is allowed, the member is said to be accessible. 2 Conversely, when access to a particular member is disallowed, the member is said to be inaccessible. 3 Access to a member is permitted when the textual location in which the access takes place is included in the accessibility domain (§10.5.2) of the member.


10.5.1 Declared accessibility Paragraph 11
The declared accessibility of a member can be one of the following: Paragraph 21 Depending on the context in which a member declaration takes place, only certain types of declared accessibility are permitted. 2 Furthermore, when a member declaration does not include any access modifiers, the context in which the declaration takes place determines the default declared accessibility.


10.5.2 Accessibility domains Paragraph 11
The accessibility domain of a member consists of the (possibly disjoint) sections of program text in which access to the member is permitted. 2 For purposes of defining the accessibility domain of a member, a member is said to be top-level if it is not declared within a type, and a member is said to be nested if it is declared within another type. 3 Furthermore, the text of an assembly is defined as all source text contained in all source files of that assembly, and the source text of a type is defined as all source text contained between the opening and closing "{" and "}" tokens in the class-body, struct-body, interface-body, or enum-body of the type (including, possibly, types that are nested within the type). Paragraph 21 The accessibility domain of a predefined type (such as object, int, or double) is unlimited. Paragraph 31 The accessibility domain of a top-level type T that is declared in a program P is defined as follows: [Note: From these definitions it follows that the accessibility domain of a top-level type is always at least the program text of the program in which that type is declared. end note] Paragraph 41 The accessibility domain of a nested member M declared in a type T within a program P, is defined as follows (noting that M itself may possibly be a type): [Note: From these definitions it follows that the accessibility domain of a nested member is always at least the program text of the type in which the member is declared. Furthermore, it follows that the accessibility domain of a member is never more inclusive than the accessibility domain of the type in which the member is declared. end note] [Note: In intuitive terms, when a type or member M is accessed, the following steps are evaluated to ensure that the access is permitted: [Example: In the example
public class A  
{  
   public static int X;  
   internal static int Y;  
   private static int Z;  
}  
internal class B  
{  
   public static int X;  
   internal static int Y;  
   private static int Z;  
   public class C  
   {  
      public static int X;  
      internal static int Y;  
      private static int Z;  
   }  
   private class D  
   {  
      public static int X;  
      internal static int Y;  
      private static int Z;  
   }  
}  
the classes and members have the following accessibility domains:
As the example illustrates, the accessibility domain of a member is never larger than that of a containing type. For example, even though all X members have public declared accessibility, all but A.X have accessibility domains that are constrained by a containing type. end example] Paragraph 51 As described in §10.4, all members of a base class, except for instance constructors, destructors, and static constructors are inherited by derived types. 2 This includes even private members of a base class. 3 However, the accessibility domain of a private member includes only the program text of the type in which the member is declared. [Example: In the example
class A  
{  
   int x;  
   static void F(B b) {  
      b.x = 1;   // Ok  
   }  
}  
class B: A  
{  
   static void F(B b) {  
      b.x = 1;   // Error, x not accessible  
   }  
}  
the B class inherits the private member x from the A class. Because the member is private, it is only accessible within the class-body of A. Thus, the access to b.x succeeds in the A.F method, but fails in the B.F method. end example]



10.5.3 Protected access for instance members Paragraph 11
When a protected instance member is accessed outside the program text of the class in which it is declared, and when a protected internal instance member is accessed outside the program text of the program in which it is declared, the access is required to take place through an instance of the derived class type in which the access occurs. 2 Let B be a base class that declares a protected instance member M, and let D be a class that derives from B. 3 Within the class-body of D, access to M can take one of the following forms: Paragraph 21 In addition to these forms of access, a derived class can access a protected instance constructor of a base class in a constructor-initializer (§17.10.1). [Example: In the example
public class A  
{  
   protected int x;  
   static void F(A a, B b) {  
      a.x = 1;   // Ok  
      b.x = 1;   // Ok  
   }  
}  
public class B: A  
{  
   static void F(A a, B b) {  
      a.x = 1;   // Error, must access through instance of B  
      b.x = 1;   // Ok  
   }  
}  
within A, it is possible to access x through instances of both A and B, since in either case the access takes place through an instance of A or a class derived from A. However, within B, it is not possible to access x through an instance of A, since A does not derive from B. end example]



10.5.4 Accessibility constraints Paragraph 11
Several constructs in the C# language require a type to be at least as accessible as a member or another type. 2 A type T is said to be at least as accessible as a member or type M if the accessibility domain of T is a superset of the accessibility domain of M. 3 In other words, T is at least as accessible as M if T is accessible in all contexts in which M is accessible. Paragraph 21 The following accessibility constraints exist: [Example: In the example
class A {...}  
public class B: A {...}  
the B class results in a compile-time error because A is not at least as accessible as B. end example]
[Example: Likewise, in the example
class A {...}  
public class B  
{  
   A F() {...}  
   internal A G() {...}  
   public A H() {...}  
}  
the H method in B results in a compile-time error because the return type A is not at least as accessible as the method. end example]



10.6 Signatures and overloading Paragraph 11
Methods, instance constructors, indexers, and operators are characterized by their signatures: Paragraph 21 Signatures are the enabling mechanism for overloading of members in classes, structs, and interfaces: [Example: The following example shows a set of overloaded method declarations along with their signatures.
interface ITest  
{  
   void F();              // F()  
   void F(int x);      // F(int)  
   void F(ref int x);     // F(ref int)  
   void F(out int x);     // F(out int)  
   void F(int x, int y);      // F(int, int)  
   int F(string s);      // F(string)  
   int F(int x);            // F(int)        error   
   void F(string[] a);     // F(string[])  
   void F(params string[] a);   // F(string[])   error  
}  
Note that any ref and out parameter modifiers (§17.5.1) are part of a signature. Thus, F(int), F(ref int), and F(out int) are all unique signatures. Also, note that the return type and the params modifier are not part of a signature, so it is not possible to overload solely based on return type or on the inclusion or exclusion of the params modifier. As such, the declarations of the methods F(int) and F(params string[]) identified above, result in a compile-time error. end example]


10.7 Scopes Paragraph 11
The scope of a name is the region of program text within which it is possible to refer to the entity declared by the name without qualification of the name. 2 Scopes can be nested, and an inner scope may redeclare the meaning of a name from an outer scope. [Note: This does not, however, remove the restriction imposed by §10.3 that within a nested block it is not possible to declare a local variable with the same name as a local variable in an enclosing block. end note] 3 The name from the outer scope is then said to be hidden in the region of program text covered by the inner scope, and access to the outer name is only possible by qualifying the name. Paragraph 21 Within the scope of a namespace, class, struct, or enumeration member it is possible to refer to the member in a textual position that precedes the declaration of the member. [Example: For example
class A  
{  
   void F() {  
      i = 1;  
   }  
   int i = 0;  
}  
Here, it is valid for F to refer to i before it is declared. end example] Paragraph 31 Within the scope of a local variable, it is a compile-time error to refer to the local variable in a textual position that precedes the local-variable-declarator of the local variable. [Example: For example
class A  
{  
   int i = 0;  
   void F() {  
      i = 1;      // Error, use precedes declaration  
      int i;  
      i = 2;  
   }  
   void G() {  
      int j = (j = 1);    // Valid  
   }  
   void H() {  
      int a = 1, b = ++a;  // Valid  
   }  
}  
In the F method above, the first assignment to i specifically does not refer to the field declared in the outer scope. Rather, it refers to the local variable and it results in a compile-time error because it textually precedes the declaration of the variable. In the G method, the use of j in the initializer for the declaration of j is valid because the use does not precede the local-variable-declarator. In the H method, a subsequent local-variable-declarator correctly refers to a local variable declared in an earlier local-variable-declarator within the same local-variable-declaration. end example] [Note: The scoping rules for local variables are designed to guarantee that the meaning of a name used in an expression context is always the same within a block. If the scope of a local variable were to extend only from its declaration to the end of the block, then in the example above, the first assignment would assign to the instance variable and the second assignment would assign to the local variable. In certain situations but not in the exampe above, this could lead to a compile-time error if the statements of the block were later to be rearranged.) The meaning of a name within a block may differ based on the context in which the name is used. In the example
using System;  
class A {}  
class Test  
{  
   static void Main() {  
      string A = "hello, world";  
      string s = A;         // expression context  
      Type t = typeof(A);       // type context  
      Console.WriteLine(s);      // writes "hello, world"  
      Console.WriteLine(t.ToString());  // writes "Type: A"  
   }  
}  
the name A is used in an expression context to refer to the local variable A and in a type context to refer to the class A. end note]



10.7.1 Name hiding Paragraph 11
The scope of an entity typically encompasses more program text than the declaration space of the entity. 2 In particular, the scope of an entity may include declarations that introduce new declaration spaces containing entities of the same name. 3 Such declarations cause the original entity to become hidden. 4 Conversely, an entity is said to be visible when it is not hidden. Paragraph 21 Name hiding occurs when scopes overlap through nesting and when scopes overlap through inheritance. 2 The characteristics of the two types of hiding are described in the following sections.


10.7.1.1 Hiding through nesting Paragraph 11
Name hiding through nesting can occur as a result of nesting namespaces or types within namespaces, as a result of nesting types within classes or structs, and as a result of parameter and local variable declarations. [Example: In the example
class A  
{  
   int i = 0;  
   void F() {  
      int i = 1;  
   }  
   void G() {  
      i = 1;  
   }  
}  
within the F method, the instance variable i is hidden by the local variable i, but within the G method, i still refers to the instance variable. end example]
Paragraph 21 When a name in an inner scope hides a name in an outer scope, it hides all overloaded occurrences of that name. [Example: In the example
class Outer  
{  
   static void F(int i) {}  
   static void F(string s) {}  
   class Inner  
   {  
      void G() {  
         F(1);    // Invokes Outer.Inner.F  
         F("Hello");  // Error  
      }  
      static void F(long l) {}  
   }  
}  
the call F(1) invokes the F declared in Inner because all outer occurrences of F are hidden by the inner declaration. For the same reason, the call F("Hello") results in a compile-time error. end example]



10.7.1.2 Hiding through inheritance Paragraph 11
Name hiding through inheritance occurs when classes or structs redeclare names that were inherited from base classes. 2 This type of name hiding takes one of the following forms: Paragraph 21 The rules governing operator declarations (§17.9) make it impossible for a derived class to declare an operator with the same signature as an operator in a base class. 2 Thus, operators never hide one another. Paragraph 31 Contrary to hiding a name from an outer scope, hiding an accessible name from an inherited scope causes a warning to be reported. [Example: In the example
class Base  
{  
   public void F() {}  
}  
class Derived: Base  
{  
   public void F() {}    // Warning, hiding an inherited name  
}  
the declaration of F in Derived causes a warning to be reported. Hiding an inherited name is specifically not an error, since that would preclude separate evolution of base classes. For example, the above situation might have come about because a later version of Base introduced an F method that wasn't present in an earlier version of the class. Had the above situation been an error, then any change made to a base class in a separately versioned class library could potentially cause derived classes to become invalid. end example]
Paragraph 41 The warning caused by hiding an inherited name can be eliminated through use of the new modifier: [Example:
class Base  
{  
   public void F() {}  
}  
class Derived: Base  
{  
   new public void F() {}  
}  
The new modifier indicates that the F in Derived is "new", and that it is indeed intended to hide the inherited member. end example] 2 A declaration of a new member hides an inherited member only within the scope of the new member. [Example:
class Base  
{  
   public static void F() {}  
}  
class Derived: Base  
{  
   new private static void F() {}  // Hides Base.F in Derived only  
}  
class MoreDerived: Derived  
{  
   static void G() { F(); }      // Invokes Base.F  
}  
In the example above, the declaration of F in Derived hides the F that was inherited from Base, but since the new F in Derived has private access, its scope does not extend to MoreDerived. Thus, the call F() in MoreDerived.G is valid and will invoke Base.F. end example]


10.8 Namespace and type names Paragraph 11
Several contexts in a C# program require a namespace-name or a type-name to be specified. 2 Either form of name is written as one or more identifiers separated by "." tokens. namespace-name : namespace-or-type-name type-name : namespace-or-type-name namespace-or-type-name : identifier namespace-or-type-name . identifier Paragraph 21 A type-name is a namespace-or-type-name that refers to a type. 2 Following resolution as described below, the namespace-or-type-name of a type-name must refer to a type, or otherwise a compile-time error occurs. Paragraph 31 A namespace-name is a namespace-or-type-name that refers to a namespace. 2 Following resolution as described below, the namespace-or-type-name of a namespace-name must refer to a namespace, or otherwise a compile-time error occurs. Paragraph 41 The meaning of a namespace-or-type-name is determined as follows:


10.8.1 Fully qualified names Paragraph 11
Every namespace and type has a fully qualified name, which uniquely identifies the namespace or type amongst all others. 2 The fully qualified name of a namespace or type N is determined as follows: Paragraph 21 In other words, the fully qualified name of N is the complete hierarchical path of identifiers that lead to N, starting from the global namespace. 2 Because every member of a namespace or type must have a unique name, it follows that the fully qualified name of a namespace or type is always unique. [Example: The example below shows several namespace and type declarations along with their associated fully qualified names.
class A {}        // A  
namespace X       // X  
{  
   class B        // X.B  
   {  
      class C {}   // X.B.C  
   }  
   namespace Y   // X.Y  
   {  
      class D {}   // X.Y.D  
   }  
}  
namespace X.Y    // X.Y  
{  
   class E {}    // X.Y.E  
}  
end example]



10.9 Automatic memory management Paragraph 11
C# employs automatic memory management, which frees developers from manually allocating and freeing the memory occupied by objects. 2 Automatic memory management policies are implemented by a garbage collector. 3 The memory management life cycle of an object is as follows: 4 1 When the object is created, memory is allocated for it, the constructor is run, and the object is considered live. 5 2 If the object, or any part of it, cannot be accessed by any possible continuation of execution, other than the running of destructors, the object is considered no longer in use, and it becomes eligible for destruction. [Note: Implementations may choose to analyze code to determine which references to an object may be used in the future. For instance, if a local variable that is in scope is the only existing reference to an object, but that local variable is never referred to in any possible continuation of execution from the current execution point in the procedure, an implementation may (but is not required to) treat the object as no longer in use. end note] 6 3 Once the object is eligible for destruction, at some unspecified later time the destructor (§17.12) (if any) for the object is run. 7 Unless overridden by explicit calls, the destructor for the object is run once only. 8 4 Once the destructor for an object is run, if that object, or any part of it, cannot be accessed by any possible continuation of execution, including the running of destructors, the object is considered inaccessible and the object becomes eligible for collection. 9 5 Finally, at some time after the object becomes eligible for collection, the garbage collector frees the memory associated with that object. Paragraph 21 The garbage collector maintains information about object usage, and uses this information to make memory management decisions, such as where in memory to locate a newly created object, when to relocate an object, and when an object is no longer in use or inaccessible. Paragraph 31 Like other languages that assume the existence of a garbage collector, C# is designed so that the garbage collector may implement a wide range of memory management policies. 2 For instance, C# does not require that destructors be run or that objects be collected as soon as they are eligible, or that destructors be run in any particular order, or on any particular thread. Paragraph 41 The behavior of the garbage collector can be controlled, to some degree, via static methods on the class System.GC. 2 This class can be used to request a collection to occur, destructors to be run (or not run), and so forth. [Example: Since the garbage collector is allowed wide latitude in deciding when to collect objects and run destructors, a conforming implementation may produce output that differs from that shown by the following code. The program
using System;  
class A  
{  
   ~A() {  
      Console.WriteLine("Destruct instance of A");  
   }  
}  
class B  
{  
   object Ref;  
   public B(object o) {  
      Ref = o;  
   }  
   ~B() {  
      Console.WriteLine("Destruct instance of B");  
   }  
}  
class Test  
{  
   static void Main() {  
      B b = new B(new A());  
      b = null;  
      GC.Collect();  
      GC.WaitForPendingFinalizers();  
   }  
}  
creates an instance of class A and an instance of class B. These objects become eligible for garbage collection when the variable b is assigned the value null, since after this time it is impossible for any user-written code to access them. The output could be either
Destruct instance of A  
Destruct instance of B  
or
Destruct instance of B  
Destruct instance of A  
because the language imposes no constraints on the order in which objects are garbage collected.
In subtle cases, the distinction between "eligible for destruction" and "eligible for collection" can be important. For example,
using System;  
class A  
{  
   ~A() {  
      Console.WriteLine("Destruct instance of A");  
   }  
   public void F() {  
      Console.WriteLine("A.F");  
      Test.RefA = this;  
   }  
}  
class B  
{  
   public A Ref;  
   ~B() {  
      Console.WriteLine("Destruct instance of B");  
      Ref.F();  
   }  
}  
class Test  
{  
   public static A RefA;  
   public static B RefB;  
   static void Main() {  
      RefB = new B();  
      RefA = new A();  
      RefB.Ref = RefA;  
      RefB = null;  
      RefA = null;  
      // A and B now eligible for destruction  
      GC.Collect();  
      GC.WaitForPendingFinalizers();  
      // B now eligible for collection, but A is not  
      if (RefA != null)  
      Console.WriteLine("RefA is not null");  
   }  
}  
In the above program, if the garbage collector chooses to run the destructor of A before the destructor of B, then the output of this program might be:
Destruct instance of A  
Destruct instance of B  
A.F  
RefA is not null  
Note that although the instance of A was not in use and A's destructor was run, it is still possible for methods of A (in this case, F) to be called from another destructor. Also, note that running of a destructor may cause an object to become usable from the mainline program again. In this case, the running of B's destructor caused an instance of A that was previously not in use to become accessible from the live reference RefA. After the call to WaitForPendingFinalizers, the instance of B is eligible for collection, but the instance of A is not, because of the reference RefA. To avoid confusion and unexpected behavior, it is generally a good idea for destructors to only perform cleanup on data stored in their object's own fields, and not to perform any actions on referenced objects or static fields. end example]


10.10 Execution order Paragraph 11
Execution shall proceed such that the side effects of each executing thread are preserved at critical execution points. 2 A side effect is defined as a read or write of a volatile field, a write to a non-volatile variable, a write to an external resource, and the throwing of an exception. 3 The critical execution points at which the order of these side effects must be preserved are references to volatile fields (§17.4.3), lock statements (§15.12), and thread creation and termination. 4 An implementation is free to change the order of execution of a C# program, subject to the following constraints:


11 Types Paragraph 11
The types of the C# language are divided into two main categories: Value types and reference types. type : value-type reference-type Paragraph 21 A third category of types, pointers, is available only in unsafe code. 2 This is discussed further in §25.2. Paragraph 31 Value types differ from reference types in that variables of the value types directly contain their data, whereas variables of the reference types store references to their data, the latter being known as objects. 2 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. 3 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. Paragraph 41 C#'s type system is unified such that a value of any type can be treated as an object. 2 Every type in C# directly or indirectly derives from the object class type, and object is the ultimate base class of all types. 3 Values of reference types are treated as objects simply by viewing the values as type object. 4 Values of value types are treated as objects by performing boxing and unboxing operations (§11.3).


11.1 Value types Paragraph 11
A value type is either a struct type or an enumeration type. 2 C# provides a set of predefined struct types called the simple types. 3 The simple types are identified through reserved words. value-type : struct-type enum-type struct-type : type-name simple-type simple-type : numeric-type bool numeric-type : integral-type floating-point-type decimal integral-type : sbyte byte short ushort int uint long ulong char floating-point-type : float double enum-type : type-name Paragraph 21 All value types implicitly inherit from class object. 2 It is not possible for any type to derive from a value type, and value types are thus implicitly sealed (§17.1.1.2). Paragraph 31 A variable of a value type always contains a value of that type. 2 Unlike reference types, it is not possible for a value of a value type to be null, or to reference an object of a more derived type. Paragraph 41 Assignment to a variable of a value type creates a copy of the value being assigned. 2 This differs from assignment to a variable of a reference type, which copies the reference but not the object identified by the reference.


11.1.1 Default constructors Paragraph 11
All value types implicitly declare a public parameterless instance constructor called the default constructor. Paragraph 21 The default constructor returns a zero-initialized instance known as the default value for the value type: Paragraph 31 Like any other instance constructor, the default constructor of a value type is invoked using the new operator. [Note: For efficiency reasons, this requirement is not intended to actually have the implementation generate a constructor call. end note] 2 In the example below, variables i and j are both initialized to zero.
class A  
{  
   void F() {  
      int i = 0;  
      int j = new int();  
   }  
}  
Paragraph 41 Because every value type implicitly has a public parameterless instance constructor, it is not possible for a struct type to contain an explicit declaration of a parameterless constructor. 2 A struct type is however permitted to declare parameterized instance constructors (§18.3.8).


11.1.2 Struct types Paragraph 11
A struct type is a value type that can declare constants, fields, methods, properties, indexers, operators, instance constructors, static constructors, and nested types. 2 Struct types are described in §18.


11.1.3 Simple types Paragraph 11
C# provides a set of predefined struct types called the simple types. 2 The simple types are identified through reserved words, but these reserved words are simply aliases for predefined struct types in the System namespace, as described in the table below.
Reserved word Aliased type
sbyte System.SByte
byte System.Byte
short System.Int16
ushort System.UInt16
int System.Int32
uint System.UInt32
long System.Int64
ulong System.UInt64
char System.Char
float System.Single
double System.Double
bool System.Boolean
decimal System.Decimal
Paragraph 21 Because a simple type aliases a struct type, every simple type has members. [Example: For example, int has the members declared in System.Int32 and the members inherited from System.Object, and the following statements are permitted:
int i = int.MaxValue;      // System.Int32.MaxValue constant  
string s = i.ToString();    // System.Int32.ToString() instance method  
string t = 123.ToString();   // System.Int32.ToString() instance method  
end example]
2 The simple types differ from other struct types in that they permit certain additional operations:



11.1.4 Integral types Paragraph 11
C# supports nine integral types: sbyte, byte, short, ushort, int, uint, long, ulong, and char. 2 The integral types have the following sizes and ranges of values: Paragraph 21 The integral-type unary and binary operators always operate with signed 32-bit precision, unsigned 32-bit precision, signed 64-bit precision, or unsigned 64-bit precision: Paragraph 31 The char type is classified as an integral type, but it differs from the other integral types in two ways: Paragraph 41 The checked and unchecked operators and statements are used to control overflow checking for integral-type arithmetic operations and conversions (§14.5.12). 2 In a checked context, an overflow produces a compile-time error or causes an System.OverflowException to be thrown. 3 In an unchecked context, overflows are ignored and any high-order bits that do not fit in the destination type are discarded.


11.1.5 Floating point types Paragraph 11
C# supports two floating-point types: float and double. 2 The float and double types are represented using the 32-bit single-precision and 64-bit double-precision IEEE 754 formats, which provide the following sets of values: Paragraph 21 The float type can represent values ranging from approximately 1.5 × 10-45 to 3.4 × 1038 with a precision of 7 digits. Paragraph 31 The double type can represent values ranging from approximately 5.0 × 10-324 to 1.7 × 10308 with a precision of 15-16 digits. Paragraph 41 If one of the operands of a binary operator is of a floating-point type, then the other operand must be of an integral type or a floating-point type, and the operation is evaluated as follows: Paragraph 51 The floating-point operators, including the assignment operators, never produce exceptions. 2 Instead, in exceptional situations, floating-point operations produce zero, infinity, or NaN, as described below: Paragraph 61 Floating-point operations may be performed with higher precision than the result type of the operation. [Example: For example, some hardware architectures support an "extended" or "long double" floating-point type with greater range and precision than the double type, and implicitly perform all floating-point operations using this higher precision type. Only at excessive cost in performance can such hardware architectures be made to perform floating-point operations with less precision, and rather than require an implementation to forfeit both performance and precision, C# allows a higher precision type to be used for all floating-point operations. Other than delivering more precise results, this rarely has any measurable effects. However, in expressions of the form x * y / z, where the multiplication produces a result that is outside the double range, but the subsequent division brings the temporary result back into the double range, the fact that the expression is evaluated in a higher range format may cause a finite result to be produced instead of an infinity. end example]


11.1.6 The decimal type Paragraph 11
The decimal type is a 128-bit data type suitable for financial and monetary calculations. 2 The decimal type can represent values ranging from 1.0 × 10-28 to approximately 7.9 × 1028 with 28-29 significant digits. Paragraph 21 The finite set of values of type decimal are of the form -1s × c × 10-e, where the sign s is 0 or 1, the coefficient c is given by 0 ≤ c < 296, and the scale e is such that 0 ≤ e ≤ 28. 2 The decimal type does not support signed zeros, infinities, or NaN's. Paragraph 31 A decimal is represented as a 96-bit integer scaled by a power of ten. 2 For decimals with an absolute value less than 1.0m, the value is exact to the 28th decimal place, but no further. 3 For decimals with an absolute value greater than or equal to 1.0m, the value is exact to 28 or 29 digits. 4 Contrary to the float and double data types, decimal fractional numbers such as 0.1 can be represented exactly in the decimal representation. 5 In the float and double representations, such numbers are often infinite fractions, making those representations more prone to round-off errors. Paragraph 41 If one of the operands of a binary operator is of type decimal, then the other operand must be of an integral type or of type decimal. 2 If an integral type operand is present, it is converted to decimal before the operation is performed. Paragraph 51 The result of an operation on values of type decimal is that which would result from calculating an exact result (preserving scale, as defined for each operator) and then rounding to fit the representation. 2 Results are rounded to the nearest representable value, and, when a result is equally close to two representable values, to the value that has an even number in the least significant digit position (this is known as "banker's rounding"). 3 That is, results are exact to 28 or 29 digits, but to no more than 28 decimal places. 4 A zero result always has a sign of 0 and a scale of 0. Paragraph 61 If a decimal arithmetic operation produces a value that is too small for the decimal format after rounding, the result of the operation becomes zero. 2 If a decimal arithmetic operation produces a result that is too large for the decimal format, a System.OverflowException is thrown. Paragraph 71 The decimal type has greater precision but smaller range than the floating-point types. 2 Thus, conversions from the floating-point types to decimal might produce overflow exceptions, and conversions from decimal to the floating-point types might cause loss of precision. 3 For these reasons, no implicit conversions exist between the floating-point types and decimal, and without explicit casts, it is not possible to mix floating-point and decimal operands in the same expression.


11.1.7 The bool type Paragraph 11
The bool type represents boolean logical quantities. 2 The possible values of type bool are true and false. Paragraph 21 No standard conversions exist between bool and other types. 2 In particular, the bool type is distinct and separate from the integral types, and a bool value cannot be used in place of an integral value, and vice versa. [Note: In the C and C++ languages, a zero integral or floating-point value, or a null pointer can be converted to the boolean value false, and a non-zero integral or floating-point value, or a non-null pointer can be converted to the boolean value true. In C#, such conversions are accomplished by explicitly comparing an integral or floating-point value to zero, or by explicitly comparing an object reference to null. end note]


11.1.8 Enumeration types Paragraph 11
An enumeration type is a distinct type with named constants. 2 Every enumeration type has an underlying type, which must be byte, sbyte, short, ushort, int, uint, long or ulong. 3 Enumeration types are defined through enumeration declarations (§21.1).


11.2 Reference types Paragraph 11
A reference type is a class type, an interface type, an array type, or a delegate type. reference-type : class-type interface-type array-type delegate-type class-type : type-name object string interface-type : type-name array-type : non-array-type rank-specifiers non-array-type : type rank-specifiers : rank-specifier rank-specifiers rank-specifier rank-specifier : [ dim-separatorsopt ] dim-separators : , dim-separators , delegate-type : type-name Paragraph 21 A reference type value is a reference to an instance of the type, the latter known as an object. 2 The special value null is compatible with all reference types and indicates the absence of an instance.


11.2.1 Class types Paragraph 11
A class type defines a data structure that contains data members (constants and fields), function members (methods, properties, events, indexers, operators, instance constructors, destructors, and static constructors), and nested types. 2 Class types support inheritance, a mechanism whereby derived classes can extend and specialize base classes. 3 Instances of class types are created using object-creation-expressions (§14.5.10.1). Paragraph 21 Class types are described in §17.


11.2.2 The object type Paragraph 11
The object class type is the ultimate base class of all other types. 2 Every type in C# directly or indirectly derives from the object class type. Paragraph 21 The keyword object is simply an alias for the predefined class System.Object.


11.2.3 The string type Paragraph 11
The string type is a sealed class type that inherits directly from object. 2 Instances of the string class represent Unicode character strings. Paragraph 21 Values of the string type can be written as string literals (§9.4.4). Paragraph 31 The keyword string is simply an alias for the predefined class System.String.


11.2.4 Interface types Paragraph 11
An interface defines a contract. 2 A class or struct that implements an interface must adhere to its contract. 3 An interface may inherit from multiple base interfaces, and a class or struct may implement multiple interfaces. Paragraph 21 Interface types are described in §20.


11.2.5 Array types Paragraph 11
An array is a data structure that contains zero or more variables which are accessed through computed indices. 2 The variables contained in an array, also called the elements of the array, are all of the same type, and this type is called the element type of the array. Paragraph 21 Array types are described in §19.


11.2.6 Delegate types Paragraph 11
A delegate is a data structure that refers to one or more methods, and for instance methods, it also refers to their corresponding object instances. [Note: The closest equivalent of a delegate in C or C++ is a function pointer, but whereas a function pointer can only reference static functions, a delegate can reference both static and instance methods. In the latter case, the delegate stores not only a reference to the method's entry point, but also a reference to the object instance on which to invoke the method. end note] Paragraph 21 Delegate types are described in §22.


11.3 Boxing and unboxing Paragraph 11
The concept of boxing and unboxing is central to C#'s type system. 2 It provides a bridge between value-types and reference-types by permitting any value of a value-type to be converted to and from type object. 3 Boxing and unboxing enables a unified view of the type system wherein a value of any type can ultimately be treated as an object.


11.3.1 Boxing conversions Paragraph 11
A boxing conversion permits any value-type to be implicitly converted to the type object or to any interface-type implemented by the value-type. 2 Boxing a value of a value-type consists of allocating an object instance and copying the value-type value into that instance. Paragraph 21 The actual process of boxing a value of a value-type is best explained by imagining the existence of a boxing class for that type. [Example: For any value-type T, the boxing class behaves as if it were declared as follows:
sealed class T_Box  
{  
   T value;  
   public T_Box(T t) {  
      value = t;  
   }  
}  
Boxing of a value v of type T now consists of executing the expression new T_Box(v), and returning the resulting instance as a value of type object. Thus, the statements
int i = 123;  
object box = i;  
conceptually correspond to
int i = 123;  
object box = new int_Box(i);  
end example]
Paragraph 31 Boxing classes like T_Box and int_Box above don't actually exist and the dynamic type of a boxed value isn't actually a class type. 2 Instead, a boxed value of type T has the dynamic type T, and a dynamic type check using the is operator can simply reference type T. [Example: For example,
int i = 123;  
object box = i;  
if (box is int) {  
   Console.Write("Box contains an int");  
}  
will output the string "Box contains an int" on the console. end example]
Paragraph 41 A boxing conversion implies making a copy of the value being boxed. 2 This is different from a conversion of a reference-type to type object, in which the value continues to reference the same instance and simply is regarded as the less derived type object. [Example: For example, given the declaration
struct Point  
{  
   public int x, y;  
   public Point(int x, int y) {  
      this.x = x;  
      this.y = y;  
   }  
}  
the following statements
Point p = new Point(10, 10);  
object box = p;  
p.x = 20;  
Console.Write(((Point)box).x);  
will output the value 10 on the console because the implicit boxing operation that occurs in the assignment of p to box causes the value of p to be copied. Had Point been declared a class instead, the value 20 would be output because p and box would reference the same instance. end example]



11.3.2 Unboxing conversions Paragraph 11
An unboxing conversion permits an explicit conversion from type object to any value-type or from any interface-type to any value-type that implements the interface-type. 2 An unboxing operation consists of first checking that the object instance is a boxed value of the given value-type, and then copying the value out of the instance. Paragraph 21 Referring to the imaginary boxing class described in the previous section, an unboxing conversion of an object box to a value-type T consists of executing the expression ((T_Box)box).value. [Example: Thus, the statements
object box = 123;  
int i = (int)box;  
conceptually correspond to
object box = new int_Box(123);  
int i = ((int_Box)box).value;  
end example]
Paragraph 31 For an unboxing conversion to a given value-type to succeed at run-time, the value of the source operand must be a reference to an object that was previously created by boxing a value of that value-type. 2 If the source operand is null or a reference to an incompatible object, a System.InvalidCastException is thrown.


12 Variables Paragraph 11
Variables represent storage locations. 2 Every variable has a type that determines what values can be stored in the variable. 3 C# is a type-safe language, and the C# compiler guarantees that values stored in variables are always of the appropriate type. 4 The value of a variable can be changed through assignment or through use of the ++ and --operators. Paragraph 21 A variable must be definitely assigned (§12.3) before its value can be obtained. Paragraph 31 As described in the following sections, variables are either initially assigned or initially unassigned. 2 An initially assigned variable has a well-defined initial value and is always considered definitely assigned. 3 An initially unassigned variable has no initial value. 4 For an initially unassigned variable to be considered definitely assigned at a certain location, an assignment to the variable must occur in every possible execution path leading to that location.


12.1 Variable categories Paragraph 11
C# defines seven categories of variables: static variables, instance variables, array elements, value parameters, reference parameters, output parameters, and local variables. 2 The sections that follow describe each of these categories. [Example: In the example
class A  
{  
   public static int x;  
   int y;  
   void F(int[] v, int a, ref int b, out int c) {  
      int i = 1;  
      c = a + b++;  
   }  
}  
x is a static variable, y is an instance variable, v[0] is an array element, a is a value parameter, b is a reference parameter, c is an output parameter, and i is a local variable. end example]



12.1.1 Static variables Paragraph 11
A field declared with the static modifier is called a static variable. 2 A static variable comes into existence before execution of the static constructor (§17.11) for its containing type, and ceases to exist when the associated application domain ceases to exist.. Paragraph 21 The initial value of a static variable is the default value (§12.2) of the variable's type. Paragraph 31 For the purposes of definite assignment checking, a static variable is considered initially assigned.


12.1.2 Instance variables Paragraph 11
A field declared without the static modifier is called an instance variable.


12.1.2.1 Instance variables in classes Paragraph 11
An instance variable of a class comes into existence when a new instance of that class is created, and ceases to exist when there are no references to that instance and the instance's destructor (if any) has executed. Paragraph 21 The initial value of an instance variable of a class is the default value (§12.2) of the variable's type. Paragraph 31 For the purpose of definite assignment checking, an instance variable is considered initially assigned.


12.1.2.2 Instance variables in structs Paragraph 11
An instance variable of a struct has exactly the same lifetime as the struct variable to which it belongs. 2 In other words, when a variable of a struct type comes into existence or ceases to exist, so too do the instance variables of the struct. Paragraph 21 The initial assignment state of an instance variable of a struct is the same as that of the containing struct variable. 2 In other words, when a struct variable is considered initially assigned, so too are its instance variables, and when a struct variable is considered initially unassigned, its instance variables are likewise unassigned.


12.1.3 Array elements Paragraph 11
The elements of an array come into existence when an array instance is created, and cease to exist when there are no references to that array instance. Paragraph 21 The initial value of each of the elements of an array is the default value (§12.2) of the type of the array elements. Paragraph 31 For the purpose of definite assignment checking, an array element is considered initially assigned.


12.1.4 Value parameters Paragraph 11
A parameter declared without a ref or out modifier is a value parameter. Paragraph 21 A value parameter comes into existence upon invocation of the function member (method, instance constructor, accessor, or operator) to which the parameter belongs, and is initialized with the value of the argument given in the invocation. 2 A value parameter ceases to exist upon return of the function member. Paragraph 31 For the purpose of definite assignment checking, a value parameter is considered initially assigned.


12.1.5 Reference parameters Paragraph 11
A parameter declared with a ref modifier is a reference parameter. Paragraph 21 A reference parameter does not create a new storage location. 2 Instead, a reference parameter represents the same storage location as the variable given as the argument in the function member invocation. 3 Thus, the value of a reference parameter is always the same as the underlying variable. Paragraph 31 The following definite assignment rules apply to reference parameters. [Note: The rules for output parameters are different, and are described in §12.1.6. end note] Paragraph 41 Within an instance method or instance accessor of a struct type, the this keyword behaves exactly as a reference parameter of the struct type (§14.5.7).


12.1.6 Output parameters Paragraph 11
A parameter declared with an out modifier is an output parameter. Paragraph 21 An output parameter does not create a new storage location. 2 Instead, an output parameter represents the same storage location as the variable given as the argument in the function member invocation. 3 Thus, the value of an output parameter is always the same as the underlying variable. Paragraph 31 The following definite assignment rules apply to output parameters. [Note: The rules for reference parameters are different, and are described in §12.1.5. end note] Paragraph 41 Within an instance constructor of a struct type, the this keyword behaves exactly as an output parameter of the struct type (§14.5.7).


12.1.7 Local variables Paragraph 11
A local variable is declared by a local-variable-declaration, which may occur in a block, a for-statement, a switch-statement, or a using-statement. Paragraph 21 The lifetime of a local variable is the portion of program execution during which storage is guaranteed to be reserved for it. 2 This lifetime extends from entry into the block, for-statement, switch-statement, or using-statement with which it is associated, until execution of that block, for-statement, switch-statement, or using-statement ends in any way. 3 (Entering an enclosed block or calling a method suspends, but does not end, execution of the current block, for-statement, switch-statement, or using-statement.) 4 If the parent block, for-statement, switch-statement, or using-statement is entered recursively, a new instance of the local variable is created each time, and its local-variable-initializer, if any, is evaluated each time. Paragraph 31 A local variable is not automatically initialized and thus has no default value. 2 For the purpose of definite assignment checking, a local variable is considered initially unassigned. 3 A local-variable-declaration may include a local-variable-initializer, in which case the variable is considered definitely assigned in its entire scope, except within the expression provided in the local-variable-initializer. Paragraph 41 Within the scope of a local variable, it is a compile-time error to refer to that local variable in a textual position that precedes its local-variable-declarator. [Note: The actual lifetime of a local variable is implementation-dependent. For example, a compiler might statically determine that a local variable in a block is only used for a small portion of that block. Using this analysis, the compiler could generate code that results in the variable's storage having a shorter lifetime than its containing block. The storage referred to by a local reference variable is reclaimed independently of the lifetime of that local reference variable (§10.9). end note] Paragraph 51 A local variable is also declared by a foreach-statement and by a specific-catch-clause for a try-statement. 2 For a foreach-statement, the local variable is an iteration variable (§15.8.4). 3 For a specific-catch-clause, the local variable is an exception variable (§15.10). 4 A local variable declared by a foreach-statement or specific-catch-clause is considered definitely assigned in its entire scope.


12.2 Default values Paragraph 11
The following categories of variables are automatically initialized to their default values: Paragraph 21 The default value of a variable depends on the type of the variable and is determined as follows: [Note: Initialization to default values is typically done by having the memory manager or garbage collector initialize memory to all-bits-zero before it is allocated for use. For this reason, it is convenient to use all-bits-zero to represent the null reference. end note]


12.3 Definite assignment Paragraph 11
At a given location in the executable code of a function member, a variable is said to be definitely assigned if the compiler can prove, by static flow analysis, that the variable has been automatically initialized or has been the target of at least one assignment. 2 The rules of definite assignment are: Paragraph 21 The definite assignment states of instance variables of a struct-type variable are tracked individually as well as collectively. 2 In additional to the rules above, the following rules apply to struct-type variables and their instance variables: Paragraph 31 Definite assignment is a requirement in the following contexts: [Note: This ensures that the function member being invoked can consider the reference parameter initially assigned. end note]


12.3.1 Initially assigned variables Paragraph 11
The following categories of variables are classified as initially assigned:


12.3.2 Initially unassigned variables Paragraph 11
The following categories of variables are classified as initially unassigned:


12.3.3 Precise rules for determining definite assignment Paragraph 11
In order to determine that each used variable is definitely assigned, the compiler must use a process that is equivalent to the one described in this section. Paragraph 21 The compiler processes the body of each function member that has one or more initially unassigned variables. 2 For each initially unassigned variable v, the compiler determines a definite assignment state for v at each of the following points in the function member: 8 The definite assignment state of v can be either: Paragraph 31 The following rules govern how the state of a variable v is determined at each location.


12.3.3.1 General rules for statements



12.3.3.2 Block statements, checked, and unchecked statements Paragraph 11
The definite assignment state of v on the control transfer to the first statement of the statement list in the block (or to the end point of the block, if the statement list is empty) is the same as the definite assignment statement of v before the block, checked, or unchecked statement.


12.3.3.3 Expression statements Paragraph 11
For an expression statement stmt that consists of the expression expr:


12.3.3.4 Declaration statements



12.3.3.5 If statements Paragraph 11
For an if statement stmt of the form:
if (expr) then-stmt else else-stmt  



12.3.3.6 Switch statements Paragraph 11
In a switch statement stmt with controlling expression expr:


12.3.3.7 While statements Paragraph 11
For a while statement stmt of the form:
while (expr) while-body  



12.3.3.8 Do statements Paragraph 11
For a do statement stmt of the form:
do do-body while (expr);   



12.3.3.9 For statements Paragraph 11
Definite assignment checking for a for statement of the form:
for (for-initializer; for-condition; for-iterator) embedded-statement  
is done as if the statement were written:
{  
   for-initializer;  
   while (for-condition) {  
      embedded-statement;  
      for-iterator;  
   }  
}  
Paragraph 21 If the for-condition is omitted from the for statement, then evaluation of definite assignment proceeds as if for-condition were replaced with true in the above expansion.


12.3.3.10 Break, continue, and goto statements Paragraph 11
The definite assignment state of v on the control flow transfer caused by a break, continue, or goto statement is the same as the definite assignment state of v at the beginning of the statement.


12.3.3.11 Throw statements Paragraph 11
For a statement stmt of the form
throw expr ;  
Paragraph 21 The definite assignment state of v at the beginning of expr is the same as the definite assignment state of v at the beginning of stmt.


12.3.3.12 Return statements Paragraph 11
For a statement stmt of the form
return expr ;   



12.3.3.13 Try-catch statements Paragraph 11
For a statement stmt of the form:
try try-block   
catch(...) catch-block-1  
...  
catch(...) catch-block-n  




12.3.3.14 Try-finally statements Paragraph 11
For a try statement stmt of the form:
try try-block finally finally-block  
7 If a control flow transfer (for example, a goto statement) is made that begins within try-block, and ends outside of try-block, then v is also considered definitely assigned on that control flow transfer if v is definitely assigned at the end-point of finally-block. 8 (This is not an only if-if v is definitely assigned for another reason on this control flow transfer, then it is still considered definitely assigned.)


12.3.3.15 Try-catch-finally statements Paragraph 11
Definite assignment analysis for a try-catch-finally statement of the form:
try try-block   
catch(...) catch-block-1  
...  
catch(...) catch-block-n  
finally finally-block  
is done as if the statement were a try-finally statement enclosing a try-catch statement:
try {  
   try try-block   
   catch(...) catch-block-1  
   ...  
   catch(...) catch-block-n  
}  
finally finally-block  
[Example: The following example demonstrates how the different blocks of a try statement (§15.10) affect definite assignment.
class A  
{  
   static void F() {  
      int i, j;  
      try {  
         goto LABEL:  
         // neither i nor j definitely assigned  
         i = 1;  
         // i definitely assigned  
      }  
      catch {  
         // neither i nor j definitely assigned  
         i = 3;  
         // i definitely assigned  
      }  
      finally {  
         // neither i nor j definitely assigned  
         j = 5;  
         // j definitely assigned  
      }  
      // i and j definitely assigned  
      LABEL:  
      // j definitely assigned  
      
   }  
}  
end example]



12.3.3.16 Foreach statements Paragraph 11
For a foreach statement stmt of the form:
foreach (type identifier in expr) embedded-statement  



12.3.3.17 Using statements Paragraph 11
For a using statement stmt of the form:
using (resource-acquisition) embedded-statement  



12.3.3.18 Lock statements Paragraph 11
For a lock statement stmt of the form:
lock (expr) embedded-statement  



12.3.3.19 General rules for simple expressions Paragraph 11
The following rule applies to these kinds of expressions: literals (§14.5.1), simple names (§14.5.2), member access expressions (§14.5.4), non-indexed base access expressions (§14.5.8), and typeof expressions (§14.5.11).


12.3.3.20 General rules for expressions with embedded expressions Paragraph 11
The following rules apply to these kinds of expressions: parenthesized expressions (§14.5.3), element access expressions (§14.5.6), base access expressions with indexing (§14.5.8), increment and decrement expressions (§14.5.9, §14.6.5), cast expressions (§14.6.6), unary +, -, ~, * expressions, binary +, -, *, /, %, <<, >>, <, <=, >, >=, ==, !=, is, as, &, |, ^ expressions (§14.7, §14.8, §14.9, §14.10), compound assignment expressions (§14.13.2), checked and unchecked expressions (§14.5.12), array and delegate creation expressions (§14.5.10). Paragraph 21 Each of these expressions has one or more sub-expressions that are unconditionally evaluated in a fixed order. [Example: For example, the binary % operator evaluates the left hand side of the operator, then the right hand side. An indexing operation evaluates the indexed expression, and then evaluates each of the index expressions, in order from left to right. end example] 2 For an expression expr, which has sub-expressions expr1, expr2, ..., exprn, evaluated in that order:


12.3.3.21 Invocation expressions and object creation expressions Paragraph 11
For an invocation expression expr of the form:
primary-expression (arg1, arg2, ..., argn)  
or an object creation expression of the form:
new type (arg1, arg2, ..., argn)  



12.3.3.22 Simple assignment expressions Paragraph 11
For an expression expr of the form w = expr-rhs: Paragraph 21 Otherwise, the definite assignment state of v after expr is the same as the definite assignment state of v after expr-rhs.


12.3.3.23 && expressions Paragraph 11
For an expression expr of the form expr-first && expr-second: [Example: In the example
class A  
{  
   static void F(int x, int y) {  
      int i;  
      if (x >= 0 && (i = y) >= 0) {  
         // i definitely assigned  
      }  
      else {  
         // i not definitely assigned  
      }  
      // i not definitely assigned  
   }  
}  
the variable i is considered definitely assigned in one of the embedded statements of an if statement but not in the other. In the if statement in method F, the variable i is definitely assigned in the first embedded statement because execution of the expression (i = y) always precedes execution of this embedded statement. In contrast, the variable i is not definitely assigned in the second embedded statement, since x >= 0 might have tested false, resulting in the variable i's being unassigned. end example]



12.3.3.24 || expressions Paragraph 11
For an expression expr of the form expr-first || expr-second: [Example: In the example
class A  
{  
   static void G(int x, int y) {  
      int i;  
      if (x >= 0 || (i = y) >= 0) {  
         // i not definitely assigned  
      }  
      else {  
         // i definitely assigned  
      }  
      // i not definitely assigned  
   }  
}  
the variable i is considered definitely assigned in one of the embedded statements of an if statement but not in the other. In the if statement in method G, the variable i is definitely assigned in the second embedded statement because execution of the expression (i = y) always precedes execution of this embedded statement. In contrast, the variable i is not definitely assigned in the first embedded statement, since x >= 0 might have tested false, resulting in the variable i's being unassigned. end example]



12.3.3.25 ! expressions Paragraph 11
For an expression expr of the form ! expr-operand:


12.3.3.26 ?: expressions Paragraph 11
For an expression expr of the form expr-cond ? expr-true : expr-false:


12.4 Variable references Paragraph 11
A variable-reference is an expression that is classified as a variable. 2 A variable-reference denotes a storage location that can be accessed both to fetch the current value and to store a new value. variable-reference : expression [Note: In C and C++, a variable-reference is known as an lvalue. end note]


12.5 Atomicity of variable references Paragraph 11
Reads and writes of the following data types shall be atomic: bool, char, byte, sbyte, short, ushort, uint, int, float, and reference types. 2 In addition, reads and writes of enum types with an underlying type in the previous list shall also be atomic. 3 Reads and writes of other types, including long, ulong, double, and decimal, as well as user-defined types, need not be atomic. 4 Aside from the library functions designed for that purpose, there is no guarantee of atomic read-modify-write, such as in the case of increment or decrement.


13 Conversions Paragraph 11
A conversion enables an expression of one type to be treated as another type. 2 Conversions can be implicit or explicit, and this determines whether an explicit cast is required. [Example: For instance, the conversion from type int to type long is implicit, so expressions of type int can implicitly be treated as type long. The opposite conversion, from type long to type int, is explicit and so an explicit cast is required.
int a = 123;  
long b = a;     // implicit conversion from int to long  
int c = (int) b;  // explicit conversion from long to int  
end example]
3 Some conversions are defined by the language. 4 Programs may also define their own conversions (§13.4).


13.1 Implicit conversions Paragraph 11
The following conversions are classified as implicit conversions: 9 Implicit conversions can occur in a variety of situations, including function member invocations (§14.4.3), cast expressions (§14.6.6), and assignments (§14.13). Paragraph 21 The pre-defined implicit conversions always succeed and never cause exceptions to be thrown. [Note: Properly designed user-defined implicit conversions should exhibit these characteristics as well. end note]


13.1.1 Identity conversion Paragraph 11
An identity conversion converts from any type to the same type. 2 This conversion exists only such that an entity that already has a required type can be said to be convertible to that type.


13.1.2 Implicit numeric conversions Paragraph 11
The implicit numeric conversions are: Paragraph 21 Conversions from int, uint, or long to float and from long to double may cause a loss of precision, but will never cause a loss of magnitude. 2 The other implicit numeric conversions never lose any information. Paragraph 31 There are no implicit conversions to the char type, so values of the other integral types do not automatically convert to the char type.


13.1.3 Implicit enumeration conversions Paragraph 11
An implicit enumeration conversion permits the decimal-integer-literal 0 to be converted to any enum-type.


13.1.4 Implicit reference conversions Paragraph 11
The implicit reference conversions are: Paragraph 21 The implicit reference conversions are those conversions between reference-types that can be proven to always succeed, and therefore require no checks at run-time. Paragraph 31 Reference conversions, implicit or explicit, never change the referential identity of the object being converted. [Note: In other words, while a reference conversion may change the type of the reference, it never changes the type or value of the object being referred to. end note]


13.1.5 Boxing conversions Paragraph 11
A boxing conversion permits any value-type to be implicitly converted to the type object or to any interface-type implemented by the value-type. 2 Boxing a value of a value-type consists of allocating an object instance and copying the value-type value into that instance. Paragraph 21 Boxing conversions are described further in §11.3.1.


13.1.6 Implicit constant expression conversions Paragraph 11
An implicit constant expression conversion permits the following conversions:


13.1.7 User-defined implicit conversions Paragraph 11
A user-defined implicit conversion consists of an optional standard implicit conversion, followed by execution of a user-defined implicit conversion operator, followed by another optional standard implicit conversion. 2 The exact rules for evaluating user-defined conversions are described in §13.4.3.


13.2 Explicit conversions Paragraph 11
The following conversions are classified as explicit conversions: Paragraph 21 Explicit conversions can occur in cast expressions (§14.6.6). Paragraph 31 The set of explicit conversions includes all implicit conversions. [Note: This means that redundant cast expressions are allowed. end note] Paragraph 41 The explicit conversions that are not implicit conversions are conversions that cannot be proven to always succeed, conversions that are known to possibly lose information, and conversions across domains of types sufficiently different to merit explicit notation.


13.2.1 Explicit numeric conversions Paragraph 11
The explicit numeric conversions are the conversions from a numeric-type to another numeric-type for which an implicit numeric conversion (§13.1.2) does not already exist: Paragraph 21 Because the explicit conversions include all implicit and explicit numeric conversions, it is always possible to convert from any numeric-type to any other numeric-type using a cast expression (§14.6.6). Paragraph 31 The explicit numeric conversions possibly lose information or possibly cause exceptions to be thrown. 2 An explicit numeric conversion is processed as follows:


13.2.2 Explicit enumeration conversions Paragraph 11
The explicit enumeration conversions are: Paragraph 21 An explicit enumeration conversion between two types is processed by treating any participating enum-type as the underlying type of that enum-type, and then performing an implicit or explicit numeric conversion between the resulting types. [Example: For example, given an enum-type E with and underlying type of int, a conversion from E to byte is processed as an explicit numeric conversion (§13.2.1) from int to byte, and a conversion from byte to E is processed as an implicit numeric conversion (§13.1.2) from byte to int. end example]


13.2.3 Explicit reference conversions Paragraph 11
The explicit reference conversions are: Paragraph 21 The explicit reference conversions are those conversions between reference-types that require run-time checks to ensure they are correct. Paragraph 31 For an explicit reference conversion to succeed at run-time, the value of the source operand must be null, or the actual type of the object referenced by the source operand must be a type that can be converted to the destination type by an implicit reference conversion (§13.1.4). 2 If an explicit reference conversion fails, a System.InvalidCastException is thrown. Paragraph 41 Reference conversions, implicit or explicit, never change the referential identity of the object being converted. [Note: In other words, while a reference conversion may change the type of the reference, it never changes the type or value of the object being referred to. end note]


13.2.4 Unboxing conversions Paragraph 11
An unboxing conversion permits an explicit conversion from type object to any value-type or from any interface-type to any value-type that implements the interface-type. 2 An unboxing operation consists of first checking that the object instance is a boxed value of the given value-type, and then copying the value out of the instance. Paragraph 21 Unboxing conversions are described further in §11.3.2.


13.2.5 User-defined explicit conversions Paragraph 11
A user-defined explicit conversion consists of an optional standard explicit conversion, followed by execution of a user-defined implicit or explicit conversion operator, followed by another optional standard explicit conversion. 2 The exact rules for evaluating user-defined conversions are described in §13.4.4.


13.3 Standard conversions Paragraph 11
The standard conversions are those pre-defined conversions that can occur as part of a user-defined conversion.


13.3.1 Standard implicit conversions Paragraph 11
The following implicit conversions are classified as standard implicit conversions: 7 The standard implicit conversions specifically exclude user-defined implicit conversions.


13.3.2 Standard explicit conversions Paragraph 11
The standard explicit conversions are all standard implicit conversions plus the subset of the explicit conversions for which an opposite standard implicit conversion exists. [Note: In other words, if a standard implicit conversion exists from a type A to a type B, then a standard explicit conversion exists from type A to type B and from type B to type A. end note]


13.4 User-defined conversions Paragraph 11
C# allows the pre-defined implicit and explicit conversions to be augmented by user-defined conversions. 2 User-defined conversions are introduced by declaring conversion operators (§17.9.3) in class and struct types.


13.4.1 Permitted user-defined conversions Paragraph 11
C# permits only certain user-defined conversions to be declared. 2 In particular, it is not possible to redefine an already existing implicit or explicit conversion. 3 A class or struct is permitted to declare a conversion from a source type S to a target type T only if all of the following are true: Paragraph 21 The restrictions that apply to user-defined conversions are discussed further in §17.9.3.


13.4.2 Evaluation of user-defined conversions Paragraph 11
A user-defined conversion converts a value from its type, called the source type, to another type, called the target type. 2 Evaluation of a user-defined conversion centers on finding the most specific user-defined conversion operator for the particular source and target types. 3 This determination is broken into several steps: Paragraph 21 Once a most specific user-defined conversion operator has been identified, the actual execution of the user-defined conversion involves up to three steps: Paragraph 31 Evaluation of a user-defined conversion never involves more than one user-defined conversion operator. 2 In other words, a conversion from type S to type T will never first execute a user-defined conversion from S to X and then execute a user-defined conversion from X to T. Paragraph 41 Exact definitions of evaluation of user-defined implicit or explicit conversions are given in the following sections. 2 The definitions make use of the following terms:


13.4.3 User-defined implicit conversions Paragraph 11
A user-defined implicit conversion from type S to type T is processed as follows:


13.4.4 User-defined explicit conversions Paragraph 11
A user-defined explicit conversion from type S to type T is processed as follows:


14 Expressions Paragraph 11
An expression is a sequence of operators and operands. 2 This chapter defines the syntax, order of evaluation of operands and operators, and meaning of expressions.


14.1 Expression classifications Paragraph 11
An expression is classified as one of the following: Paragraph 21 The final result of an expression is never a namespace, type, method group, or event access. 2 Rather, as noted above, these categories of expressions are intermediate constructs that are only permitted in certain contexts. Paragraph 31 A property access or indexer access is always reclassified as a value by performing an invocation of the get-accessor or the set-accessor. 2 The particular accessor is determined by the context of the property or indexer access: If the access is the target of an assignment, the set-accessor is invoked to assign a new value (§14.13.1). 3 Otherwise, the get-accessor is invoked to obtain the current value (§14.1.1).


14.1.1 Values of expressions Paragraph 11
Most of the constructs that involve an expression ultimately require the expression to denote a value. 2 In such cases, if the actual expression denotes a namespace, a type, a method group, or nothing, a compile-time error occurs. 3 However, if the expression denotes a property access, an indexer access, or a variable, the value of the property, indexer, or variable is implicitly substituted:


14.2 Operators Paragraph 11
Expressions are constructed from operands and operators. 2 The operators of an expression indicate which operations to apply to the operands. 3 Examples of operators include +, -, *, /, and new. 4 Examples of operands include literals, fields, local variables, and expressions. Paragraph 21 There are three kinds of operators: Paragraph 31 The order of evaluation of operators in an expression is determined by the precedence and associativity of the operators (§14.2.1). Paragraph 41 The order in which operands in an expression are evaluated, is left to right. [Example: For example, in F(i) + G(i++) * H(i), method F is called using the old value of i, then method G is called with the old value of i, and, finally, method H is called with the new value of i. This is separate from and unrelated to operator precedence. end example] 2 Certain operators can be overloaded. 3 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 (§14.2.2).


14.2.1 Operator precedence and associativity Paragraph 11
When an expression contains multiple operators, the precedence of the operators controls the order in which the individual operators are evaluated. [Note: For example, the expression x + y * z is evaluated as x + (y * z) because the * operator has higher precedence than the binary + operator. end note] 2 The precedence of an operator is established by the definition of its associated grammar production. [Note: For example, an additive-expression consists of a sequence of multiplicative-expressions separated by + or -operators, thus giving the + and -operators lower precedence than the *, /, and % operators. end note] Paragraph 21 The following table summarizes all operators in order of precedence from highest to lowest:
Section Category Operators
14.5 Primary x.y f(x) [x] x++ x-- new
typeof checked unchecked
14.6 Unary + - ! ~ ++x --x (T)x
14.7 Multiplicative * / %
14.7 Additive + -
14.8 Shift << >>
14.9 Relational and
type-testing
< > <= >= is as
14.9 Equality == !=
14.10 Logical AND &
14.10 Logical XOR ^
14.10 Logical OR |
14.11 Conditional AND &&
14.11 Conditional OR ||
14.12 Conditional ?:
14.13 Assignment = *= /= %= +-= -= <<= >>= &= ^= |=
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:
Paragraph 31 Precedence and associativity can be controlled using parentheses. [Example: For example, x + y * z first multiplies y by z and then adds the result to x, but (x + y) * z first adds x and y and then multiplies the result by z. end example]


14.2.2 Operator overloading Paragraph 11
All unary and binary operators have predefined implementations that are automatically available in any expression. 2 In addition to the predefined implementations, user-defined implementations can be introduced by including operator declarations in classes and structs (§17.9). 3 User-defined operator implementations always take precedence over predefined operator implementations: Only when no applicable user-defined operator implementations exist will the predefined operator implementations be considered. Paragraph 21 The overloadable unary operators are:
+   -   !   ~   ++   --   true   false  
[Note: Although true and false are not used explicitly in expressions, they are considered operators because they are invoked in several expression contexts: boolean expressions (§14.16) and expressions involving the conditional (§14.12), and conditional logical operators (§14.11). end note] 2 The overloadable binary operators are:
+   -   *   /   %   &   |   ^   <<   >>   ==   !=   >   <   >=   <=  
Paragraph 31 Only the operators listed above can be overloaded. 2 In particular, it is not possible to overload member access, method invocation, or the =, &&, ||, ?:, checked, unchecked, new, typeof, as, and is operators. Paragraph 41 When a binary operator is overloaded, the corresponding assignment operator, if any, is also implicitly overloaded. 2 For example, an overload of operator * is also an overload of operator *=. 3 This is described further in §14.13. 4 Note that the assignment operator itself (=) cannot be overloaded. 5 An assignment always performs a simple bit-wise copy of a value into a variable. Paragraph 51 Cast operations, such as (T)x, are overloaded by providing user-defined conversions (§13.4). Paragraph 61 Element access, such as a[x], is not considered an overloadable operator. 2 Instead, user-defined indexing is supported through indexers (§17.8). Paragraph 71 In expressions, operators are referenced using operator notation, and in declarations, operators are referenced using functional notation. 2 The following table shows the relationship between operator and functional notations for unary and binary operators. 3 In the first entry, op denotes any overloadable unary prefix operator. 4 In the second entry, op denotes the unary postfix ++ and --operators. 5 In the third entry, op denotes any overloadable binary operator. [Note: For an example of overloading the ++ and --operators see §17.9.1. end note]
Operator notation Functional notation
op x operator op(x)
x op operator op(x)
x op y operator op(x,y)
Paragraph 81 User-defined operator declarations always require at least one of the parameters to be of the class or struct type that contains the operator declaration. [Note: Thus, it is not possible for a user-defined operator to have the same signature as a predefined operator. end note] Paragraph 91 User-defined operator declarations cannot modify the syntax, precedence, or associativity of an operator. [Example: For example, the / operator is always a binary operator, always has the precedence level specified in §14.2.1, and is always left-associative. end example] [Note: While it is possible for a user-defined operator to perform any computation it pleases, implementations that produce results other than those that are intuitively expected are strongly discouraged. For example, an implementation of operator == should compare the two operands for equality and return an appropriate bool result. end note] Paragraph 101 The descriptions of individual operators in §14.5 through §14.13 specify the predefined implementations of the operators and any additional rules that apply to each operator. 2 The descriptions make use of the terms unary operator overload resolution, binary operator overload resolution, and numeric promotion, definitions of which are found in the following sections.


14.2.3 Unary operator overload resolution Paragraph 11
An operation of the form op x or x op, where op is an overloadable unary operator, and x is an expression of type X, is processed as follows:


14.2.4 Binary operator overload resolution Paragraph 11
An operation of the form x op y, where op is an overloadable binary operator, x is an expression of type X, and y is an expression of type Y, is processed as follows:


14.2.5 Candidate user-defined operators Paragraph 11
Given a type T and an operation operator op(A), where op is an overloadable operator and A is an argument list, the set of candidate user-defined operators provided by T for operator op(A) is determined as follows:


14.2.6 Numeric promotionsThis clause is informative. Numeric promotion consists of automatically performing certain implicit conversions of the operands of the predefined unary and binary numeric operators. Numeric promotion is not a distinct mechanism, but rather an effect of applying overload resolution to the predefined operators. Numeric promotion specifically does not affect evaluation of user-defined operators, although user-defined operators can be implemented to exhibit similar effects. As an example of numeric promotion, consider the predefined implementations of the binary * operator:
int operator *(int x, int y);  
uint operator *(uint x, uint y);  
long operator *(long x, long y);  
ulong operator *(ulong x, ulong y);  
float operator *(float x, float y);  
double operator *(double x, double y);  
decimal operator *(decimal x, decimal y);  
When overload resolution rules (
§14.4.2) are applied to this set of operators, the effect is to select the first of the operators for which implicit conversions exist from the operand types. [Example: For example, for the operation b * s, where b is a byte and s is a short, overload resolution selects operator *(int, int) as the best operator. Thus, the effect is that b and s are converted to int, and the type of the result is int. Likewise, for the operation i * d, where i is an int and d is a double, overload resolution selects operator *(double, double) as the best operator. end example] End of informative text.


14.2.6.1 Unary numeric promotionsThis clause is informative. Unary numeric promotion occurs for the operands of the predefined +, -, and ~ unary operators. Unary numeric promotion simply consists of converting operands of type sbyte, byte, short, ushort, or char to type int. Additionally, for the unary -operator, unary numeric promotion converts operands of type uint to type long. End of informative text.



14.2.6.2 Binary numeric promotionsThis clause is informative. Binary numeric promotion occurs for the operands of the predefined +, -, *, /, %, &, |, ^, ==, !=, >, <, >=, and <= binary operators. Binary numeric promotion implicitly converts both operands to a common type which, in case of the non-relational operators, also becomes the result type of the operation. Binary numeric promotion consists of applying the following rules, in the order they appear here:
  • If either operand is of type decimal, the other operand is converted to type decimal, or a compile-time error occurs if the other operand is of type float or double.
  • Otherwise, if either operand is of type double, the other operand is converted to type double.
  • Otherwise, if either operand is of type float, the other operand is converted to type float.
  • Otherwise, if either operand is of type ulong, the other operand is converted to type ulong, or a compile-time error occurs if the other operand is of type sbyte, short, int, or long.
  • Otherwise, if either operand is of type long, the other operand is converted to type long.
  • Otherwise, if either operand is of type uint and the other operand is of type sbyte, short, or int, both operands are converted to type long.
  • Otherwise, if either operand is of type uint, the other operand is converted to type uint.
  • Otherwise, both operands are converted to type int.
[Note: Note that the first rule disallows any operations that mix the decimal type with the double and float types. The rule follows from the fact that there are no implicit conversions between the decimal type and the double and float types. end note] [Note: Also note that it is not possible for an operand to be of type ulong when the other operand is of a signed integral type. The reason is that no integral type exists that can represent the full range of ulong as well as the signed integral types. end note] In both of the above cases, a cast expression can be used to explicitly convert one operand to a type that is compatible with the other operand. [Example: In the example
decimal AddPercent(decimal x, double percent) {  
   return x * (1.0 + percent / 100.0);  
}  
a compile-time error occurs because a decimal cannot be multiplied by a double. The error is resolved by explicitly converting the second operand to decimal, as follows:
decimal AddPercent(decimal x, double percent) {  
   return x * (decimal)(1.0 + percent / 100.0);  
}  
end example]
End of informative text.



14.3 Member lookup Paragraph 11
A member lookup is the process whereby the meaning of a name in the context of a type is determined. 2 A member lookup may occur as part of evaluating a simple-name (§14.5.2) or a member-access (§14.5.4) in an expression. Paragraph 21 A member lookup of a name N in a type T is processed as follows: Paragraph 31 For member lookups in types other than interfaces, and member lookups in interfaces that are strictly single-inheritance (each interface in the inheritance chain has exactly zero or one direct base interface), the effect of the lookup rules is simply that derived members hide base members with the same name or signature. 2 Such single-inheritance lookups are never ambiguous. 3 The ambiguities that can possibly arise from member lookups in multiple-inheritance interfaces are described in §20.2.5.


14.3.1 Base types Paragraph 11
For purposes of member lookup, a type T is considered to have the following base types:


14.4 Function members Paragraph 11
Function members are members that contain executable statements. 2 Function members are always members of types and cannot be members of namespaces. 3 C# defines the following categories of function members: 12 Except for static constructors and destructors (which cannot be invoked explicitly), the statements contained in function members are executed through function member invocations. 13 The actual syntax for writing a function member invocation depends on the particular function member category. Paragraph 21 The argument list (§14.4.1) of a function member invocation provides actual values or variable references for the parameters of the function member. Paragraph 31 Invocations of methods, indexers, operators, and instance constructors employ overload resolution to determine which of a candidate set of function members to invoke. 2 This process is described in §14.4.2. Paragraph 41 Once a particular function member has been identified at compile-time, possibly through overload resolution, the actual run-time process of invoking the function member is described in §14.4.3. [Note: The following table summarizes the processing that takes place in constructs involving the six categories of function members that can be explicitly invoked. In the table, e, x, y, and value indicate expressions classified as variables or values, T indicates an expression classified as a type, F is the simple name of a method, and P is the simple name of a property.
Construct Example          Description
Method
invocation
F(x,y) Overload resolution is applied to select the best method F in the containing class or struct. The method is invoked with the argument list (x, y). If the method is not static, the instance expression is this.
T.F(x,y) Overload resolution is applied to select the best method F in the class or struct T. A compile-time error occurs if the method is not static. The method is invoked with the argument list (x, y).
e.F(x,y) Overload resolution is applied to select the best method F in the class, struct, or interface given by the type of e. A compile-time error occurs if the method is static. The method is invoked with the instance expression e and the argument list (x, y).
Property
access
P The get accessor of the property P in the containing class or struct is invoked. A compile-time error occurs if P is writeonly. If P is not static, the instance expression is this.
P = value The set accessor of the property P in the containing class or struct is invoked with the argument list (value). A compiletime error occurs if P is read-only. If P is not static, the instance expression is this.
T.P The get accessor of the property P in the class or struct T is invoked. A compile-time error occurs if P is not static or if P is write-only.
T.P = value The set accessor of the property P in the class or struct T is invoked with the argument list (value). A compile-time error occurs if P is not static or if P is read-only.
e.P The get accessor of the property P in the class, struct, or interface given by the type of e is invoked with the instance expression e. A compile-time error occurs if P is static or if P is write-only.
e.P = value The set accessor of the property P in the class, struct, or interface given by the type of e is invoked with the instance expression e and the argument list (value). A compile-time error occurs if P is static or if P is read-only.
Event
access
E += value The add accessor of the event E in the containing class or struct is invoked. If E is not static, the instance expression is this.
E -= value The remove accessor of the event E in the containing class or struct is invoked. If E is not static, the instance expression is this.
T.E += value The add accessor of the event E in the class or struct T is invoked. A compile-time error occurs if E is not static.
T.E -= value The remove accessor of the event E in the class or struct T is invoked. A compile-time error occurs if E is not static.
e.E += value The add accessor of the event E in the class, struct, or interface given by the type of e is invoked with the instance expression e. A compile-time error occurs if E is static.
e.E -= value The remove accessor of the event E in the class, struct, or interface given by the type of e is invoked with the instance expression e. A compile-time error occurs if E is static.
Indexer
access
e[x,y] Overload resolution is applied to select the best indexer in the class, struct, or interface given by the type of e. The get accessor of the indexer is invoked with the instance expression e and the argument list (x, y). A compile-time error occurs if the indexer is write-only.
e[x,y] = value Overload resolution is applied to select the best indexer in the class, struct, or interface given by the type of e. The set accessor of the indexer is invoked with the instance expression e and the argument list (x, y, value). A compile-time error occurs if the indexer is read-only.
Operator
invocation
-x Overload resolution is applied to select the best unary operator in the class or struct given by the type of x. The selected operator is invoked with the argument list (x).
x + y Overload resolution is applied to select the best binary operator in the classes or structs given by the types of x and y. The selected operator is invoked with the argument list (x, y).
Instance
constructor
invocation
new T(x,y) Overload resolution is applied to select the best instance constructor in the class or struct T. The instance constructor is invoked with the argument list (x, y).
end note]



14.4.1 Argument lists Paragraph 11
Every function member invocation includes an argument list, which provides actual values or variable references for the parameters of the function member. 2 The syntax for specifying the argument list of a function member invocation depends on the function member category: Paragraph 21 The arguments of properties (§17.6), events (§17.7), indexers (§17.8), and user-defined operators (§17.9) are always passed as value parameters (§17.5.1.1). 2 Reference and output parameters are not supported for these categories of function members. Paragraph 31 The arguments of an instance constructor, method, or delegate invocation are specified as an argument-list: argument-list : argument argument-list , argument argument : expression ref variable-reference out variable-reference Paragraph 41 An argument-list consists of one or more arguments, separated by commas. 2 Each argument can take one of the following forms: Paragraph 51 During the run-time processing of a function member invocation (§14.4.3), the expressions or variable references of an argument list are evaluated in order, from left to right, as follows: Paragraph 61 Methods, indexers, and instance constructors may declare their right-most parameter to be a parameter array (§17.5.1.4). 2 Such function members are invoked either in their normal form or in their expanded form depending on which is applicable (§14.4.2.1): Paragraph 71 The expressions of an argument list are always evaluated in the order they are written. [Example: Thus, the example
class Test  
{  
   static void F(int x, int y, int z) {  
      System.Console.WriteLine("x = {0}, y = {1}, z = {2}", x, y, z);  
   }  
   static void Main() {  
      int i = 0;  
      F(i++, i++, i++);  
   }  
}  
produces the output
x = 0, y = 1, z = 2  
end example]
Paragraph 81 The array covariance rules (§19.5) permit a value of an array type A[] to be a reference to an instance of an array type B[], provided an implicit reference conversion exists from B to A. 2 Because of these rules, when an array element of a reference-type is passed as a reference or output parameter, a run-time check is required to ensure that the actual element type of the array is identical to that of the parameter. [Example: In the example
class Test  
{  
   static void F(ref object x) {...}  
   static void Main() {  
      object[] a = new object[10];  
      object[] b = new string[10];  
      F(ref a[0]);    // Ok  
      F(ref b[1]);   // ArrayTypeMismatchException  
   }  
}  
the second invocation of F causes a System.ArrayTypeMismatchException to be thrown because the actual element type of b is string and not object. end example]
Paragraph 91 When a function member with a parameter array is invoked in its expanded form, the invocation is processed exactly as if an array creation expression with an array initializer (§14.5.10.2) was inserted around the expanded parameters. [Example: For example, given the declaration
void F(int x, int y, params object[] args);  
the following invocations of the expanded form of the method
F(10, 20);  
F(10, 20, 30, 40);  
F(10, 20, 1, "hello", 3.0);  
correspond exactly to
F(10, 20, new object[] {});  
F(10, 20, new object[] {30, 40});  
F(10, 20, new object[] {1, "hello", 3.0});  
end example]
2 In particular, note that an empty array is created when there are zero arguments given for the parameter array.



14.4.2 Overload resolution Paragraph 11
Overload resolution is a compile-time mechanism for selecting the best function member to invoke given an argument list and a set of candidate function members. 2 Overload resolution selects the function member to invoke in the following distinct contexts within C#: Paragraph 21 Each of these contexts defines the set of candidate function members and the list of arguments in its own unique way. 2 However, once the candidate function members and the argument list have been identified, the selection of the best function member is the same in all cases: Paragraph 31 The following sections define the exact meanings of the terms applicable function member and better function member.


14.4.2.1 Applicable function member Paragraph 11
A function member is said to be an applicable function member with respect to an argument list A when all of the following are true: Paragraph 21 For a function member that includes a parameter array, if the function member is applicable by the above rules, it is said to be applicable in its normal form. 2 If a function member that includes a parameter array is not applicable in its normal form, the function member may instead be applicable in its expanded form:


14.4.2.2 Better function member Paragraph 11
Given an argument list A with a set of argument types A1, A2, ..., AN and two applicable function members MP and MQ with parameter types P1, P2, ..., PN and Q1, Q2, ..., QN, MP is defined to be a better function member than MQ if Paragraph 21 When performing this evaluation, if MP or MQ is applicable in its expanded form, then PX or QX refers to a parameter in the expanded form of the parameter list.


14.4.2.3 Better conversion Paragraph 11
Given an implicit conversion C1 that converts from a type S to a type T1, and an implicit conversion C2 that converts from a type S to a type T2, the better conversion of the two conversions is determined as follows: Paragraph 21 If an implicit conversion C1 is defined by these rules to be a better conversion than an implicit conversion C2, then it is also the case that C2 is a worse conversion than C1.


14.4.3 Function member invocation Paragraph 11
This section describes the process that takes place at run-time to invoke a particular function member. 2 It is assumed that a compile-time process has already determined the particular member to invoke, possibly by applying overload resolution to a set of candidate function members. Paragraph 21 For purposes of describing the invocation process, function members are divided into two categories: Paragraph 31 The run-time processing of a function member invocation consists of the following steps, where M is the function member and, if M is an instance member, E is the instance expression:


14.4.3.1 Invocations on boxed instances Paragraph 11
A function member implemented in a value-type can be invoked through a boxed instance of that value-type in the following situations: Paragraph 21 In these situations, the boxed instance is considered to contain a variable of the value-type, and this variable becomes the variable referenced by this within the function member invocation. [Note: In particular, this means that when a function member is invoked on a boxed instance, it is possible for the function member to modify the value contained in the boxed instance. end note]


14.5 Primary expressions Paragraph 11
Primary expressions include the simplest forms of expressions. primary-expression : array-creation-expression primary-no-array-creation-expression primary-no-array-creation-expression : literal simple-name parenthesized-expression member-access invocation-expression element-access this-access base-access post-increment-expression post-decrement-expression object-creation-expression delegate-creation-expression typeof-expression sizeof-expression checked-expression unchecked-expression Paragraph 21 Primary expressions are divided between array-creation-expressions and primary-no-array-creation-expressions. 2 Treating array-creation-expression in this way, rather than listing it along with the other simple expression forms, enables the grammar to disallow potentially confusing code such as
object o = new int[3][1];  
which would otherwise be interpreted as
object o = (new int[3])[1];  



14.5.1 Literals Paragraph 11
A primary-expression that consists of a literal (§9.4.4) is classified as a value.


14.5.2 Simple names Paragraph 11
A simple-name consists of a single identifier. simple-name : identifier Paragraph 21 A simple-name is evaluated and classified as follows:


14.5.2.1 Invariant meaning in blocks Paragraph 11
For each occurrence of a given identifier as a simple-name in an expression, every other occurrence of the same identifier as a simple-name in an expression within the immediately enclosing block (§15.2) or switch-block (§15.7.2) must refer to the same entity. 2 This rule ensures that the meaning of a name in the context of an expression is always the same within a block. Paragraph 21 The example
class Test  
{  
   double x;  
   void F(bool b) {  
      x = 1.0;  
      if (b) {  
         int x = 1;  
      }  
   }  
}  
results in a compile-time error because x refers to different entities within the outer block (the extent of which includes the nested block in the if statement).
2 In contrast, the example
class Test  
{  
   double x;  
   void F(bool b) {  
      if (b) {  
         x = 1.0;  
      }  
      else {  
         int x = 1;  
      }  
   }  
}  
is permitted because the name x is never used in the outer block.
Paragraph 31 Note that the rule of invariant meaning applies only to simple names. 2 It is perfectly valid for the same identifier to have one meaning as a simple name and another meaning as right operand of a member access (§14.5.4). [Example: For example:
struct Point  
{  
   int x, y;  
   public Point(int x, int y) {  
      this.x = x;  
      this.y = y;  
   }  
}  
The example above illustrates a common pattern of using the names of fields as parameter names in an instance constructor. In the example, the simple names x and y refer to the parameters, but that does not prevent the member access expressions this.x and this.y from accessing the fields. end example]


14.5.3 Parenthesized expressions Paragraph 11
A parenthesized-expression consists of an expression enclosed in parentheses. parenthesized-expression : ( expression ) Paragraph 21 A parenthesized-expression is evaluated by evaluating the expression within the parentheses. 2 If the expression within the parentheses denotes a namespace, type, or method group, a compile-time error occurs. 3 Otherwise, the result of the parenthesized-expression is the result of the evaluation of the contained expression.


14.5.4 Member access Paragraph 11
A member-access consists of a primary-expression or a predefined-type, followed by a "." token, followed by an identifier. member-access : primary-expression . identifier predefined-type . identifier predefined-type : one of bool byte char decimal double float int long object sbyte short string uint ulong ushort Paragraph 21 A member-access of the form E.I, where E is a primary-expression or a predefined-type and I is an identifier, is evaluated and classified as follows:


14.5.4.1 Identical simple names and type names Paragraph 11
In a member access of the form E.I, if E is a single identifier, and if the meaning of E as a simple-name (§14.5.2) is a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name (§10.8), then both possible meanings of E are permitted. 2 The two possible meanings of E.I are never ambiguous, since I must necessarily be a member of the type E in both cases. 3 In other words, the rule simply permits access to the static members of E where a compile-time error would otherwise have occurred. [Example: For example:
struct Color  
{  
   public static readonly Color White = new Color(...);  
   public static readonly Color Black = new Color(...);  
   public Color Complement() {...}  
}  
class A  
{  
   public Color Color;          // Field Color of type Color  
   void F() {  
      Color = Color.Black;       // References Color.Black static member  
      
      Color = Color.Complement();  // Invokes Complement() on Color field  
      
   }  
   static void G() {  
      Color c = Color.White;    // References Color.White static member  
      
   }  
}  
Within the A class, those occurrences of the Color identifier that reference the Color type are underlined, and those that reference the Color field are not underlined. end example]


14.5.5 Invocation expressions Paragraph 11
An invocation-expression is used to invoke a method. invocation-expression : primary-expression ( argument-listopt ) Paragraph 21 The primary-expression of an invocation-expression must be a method group or a value of a delegate-type. 2 If the primary-expression is a method group, the invocation-expression is a method invocation (§14.5.5.1). 3 If the primary-expression is a value of a delegate-type, the invocation-expression is a delegate invocation (§14.5.5.2). 4 If the primary-expression is neither a method group nor a value of a delegate-type, a compile-time error occurs. Paragraph 31 The optional argument-list (§14.4.1) provides values or variable references for the parameters of the method. Paragraph 41 The result of evaluating an invocation-expression is classified as follows:


14.5.5.1 Method invocations Paragraph 11
For a method invocation, the primary-expression of the invocation-expression must be a method group. 2 The method group identifies the one method to invoke or the set of overloaded methods from which to choose a specific method to invoke. 3 In the latter case, determination of the specific method to invoke is based on the context provided by the types of the arguments in the argument-list. Paragraph 21 The compile-time processing of a method invocation of the form M(A), where M is a method group and A is an optional argument-list, consists of the following steps: Paragraph 31 Once a method has been selected and validated at compile-time by the above steps, the actual run-time invocation is processed according to the rules of function member invocation described in §14.4.3. [Note: The intuitive effect of the resolution rules described above is as follows: To locate the particular method invoked by a method invocation, start with the type indicated by the method invocation and proceed up the inheritance chain until at least one applicable, accessible, non-override method declaration is found. Then perform overload resolution on the set of applicable, accessible, non-override methods declared in that type and invoke the method thus selected. end note]


14.5.5.2 Delegate invocations Paragraph 11
For a delegate invocation, the primary-expression of the invocation-expression must be a value of a delegate-type. 2 Furthermore, considering the delegate-type to be a function member with the same parameter list as the delegate-type, the delegate-type must be applicable (§14.4.2.1) with respect to the argument-list of the invocation-expression. Paragraph 21 The run-time processing of a delegate invocation of the form D(A), where D is a primary-expression of a delegate-type and A is an optional argument-list, consists of the following steps:


14.5.6 Element access Paragraph 11
An element-access consists of a primary-no-array-creation-expression, followed by a "[" token, followed by an expression-list, followed by a "]" token. 2 The expression-list consists of one or more expressions, separated by commas. element-access : primary-no-array-creation-expression [ expression-list ] expression-list : expression expression-list , expression Paragraph 21 If the primary-no-array-creation-expression of an element-access is a value of an array-type, the element-access is an array access (§14.5.6.1). 2 Otherwise, the primary-no-array-creation-expression must be a variable or value of a class, struct, or interface type that has one or more indexer members, in which case the element-access is an indexer access (§14.5.6.2).


14.5.6.1 Array access Paragraph 11
For an array access, the primary-no-array-creation-expression of the element-access must be a value of an array-type. 2 The number of expressions in the expression-list must be the same as the rank of the array-type, and each expression must be of type int, uint, long, ulong, or of a type that can be implicitly converted to one or more of these types. Paragraph 21 The result of evaluating an array access is a variable of the element type of the array, namely the array element selected by the value(s) of the expression(s) in the expression-list. Paragraph 31 The run-time processing of an array access of the form P[A], where P is a primary-no-array-creation-expression of an array-type and A is an expression-list, consists of the following steps:


14.5.6.2 Indexer access Paragraph 11
For an indexer access, the primary-no-array-creation-expression of the element-accessmust be a variable or value of a class, struct, or interface type, and this type must implement one or more indexers that are applicable with respect to the expression-list of the element-access. Paragraph 21 The compile-time processing of an indexer access of the form P[A], where P is a primary-no-array-creation-expression of a class, struct, or interface type T, and A is an expression-list, consists of the following steps: Paragraph 31 Depending on the context in which it is used, an indexer access causes invocation of either the get-accessor or the set-accessor of the indexer. 2 If the indexer access is the target of an assignment, the set-accessor is invoked to assign a new value (§14.13.1). 3 In all other cases, the get-accessor is invoked to obtain the current value (§14.1.1).


14.5.7 This access Paragraph 11
A this-access consists of the reserved word this. this-access : this Paragraph 21 A this-access is permitted only in the block of an instance constructor, an instance method, or an instance accessor. 2 It has one of the following meanings: Paragraph 31 Use of this in a primary-expression in a context other than the ones listed above is a compile-time error. 2 In particular, it is not possible to refer to this in a static method, a static property accessor, or in a variable-initializer of a field declaration.


14.5.8 Base access Paragraph 11
A base-access consists of the reserved word base followed by either a "." token and an identifier or an expression-list enclosed in square brackets: base-access : base . identifier base [ expression-list ] Paragraph 21 A base-access is used to access base class members that are hidden by similarly named members in the current class or struct. 2 A base-access is permitted only in the block of an instance constructor, an instance method, or an instance accessor. 3 When base.I occurs in a class or struct, I must denote a member of the base class of that class or struct. 4 Likewise, when base[E] occurs in a class, an applicable indexer must exist in the base class. Paragraph 31 At compile-time, base-access expressions of the form base.I and base[E] are evaluated exactly as if they were written ((B)this).I and ((B)this)[E], where B is the base class of the class or struct in which the construct occurs. 2 Thus, base.I and base[E] correspond to this.I and this[E], except this is viewed as an instance of the base class. Paragraph 41 When a base-access references a virtual function member (a method, property, or indexer), the determination of which function member to invoke at run-time (§14.4.3) is changed. 2 The function member that is invoked is determined by finding the most derived implementation (§17.5.3) of the function member with respect to B (instead of with respect to the run-time type of this, as would be usual in a non-base access). 3 Thus, within an override of a virtual function member, a base-access can be used to invoke the inherited implementation of the function member. 4 If the function member referenced by a base-access is abstract, a compile-time error occurs.


14.5.9 Postfix increment and decrement operators
post-increment-expression : primary-expression ++ post-decrement-expression : primary-expression -- Paragraph 11 The operand of a postfix increment or decrement operation must be an expression classified as a variable, a property access, or an indexer access. 2 The result of the operation is a value of the same type as the operand. Paragraph 21 If the operand of a postfix increment or decrement operation is a property or indexer access, the property or indexer must have both a get and a set accessor. 2 If this is not the case, a compile-time error occurs. Paragraph 31 Unary operator overload resolution (§14.2.3) is applied to select a specific operator implementation. 2 Predefined ++ and --operators exist for the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, and any enum type. 3 The predefined ++ operators return the value produced by adding 1 to the operand, and the predefined --operators return the value produced by subtracting 1 from the operand. Paragraph 41 The run-time processing of a postfix increment or decrement operation of the form x++ or x--consists of the following steps: Paragraph 51 The ++ and --operators also support prefix notation (§14.6.5). 2 The result of x++ or x--is the value of x before the operation, whereas the result of ++x or --x is the value of x after the operation. 3 In either case, x itself has the same value after the operation. Paragraph 61 An operator ++ or operator --implementation can be invoked using either postfix or prefix notation. 2 It is not possible to have separate operator implementations for the two notations.


14.5.10 The new operator Paragraph 11
The new operator is used to create new instances of types. Paragraph 21 There are three forms of new expressions: Paragraph 31 The new operator implies creation of an instance of a type, but does not necessarily imply dynamic allocation of memory. 2 In particular, instances of value types require no additional memory beyond the variables in which they reside, and no dynamic allocations occur when new is used to create instances of value types.


14.5.10.1 Object creation expressions Paragraph 11
An object-creation-expression is used to create a new instance of a class-type or a value-type. object-creation-expression : new type ( argument-listopt ) Paragraph 21 The type of an object-creation-expression must be a class-type or a value-type. 2 The type cannot be an abstract class-type. Paragraph 31 The optional argument-list (§14.4.1) is permitted only if the type is a class-type or a struct-type. Paragraph 41 The compile-time processing of an object-creation-expression of the form new T(A), where T is a class-type or a value-type and A is an optional argument-list, consists of the following steps: Paragraph 51 The run-time processing of an object-creation-expression of the form new T(A), where T is class-type or a struct-type and A is an optional argument-list, consists of the following steps:


14.5.10.2 Array creation expressions Paragraph 11
An array-creation-expression is used to create a new instance of an array-type. array-creation-expression : new non-array-type [ expression-list ] rank-specifiersopt array-initializeropt new array-type array-initializer Paragraph 21 An array creation expression of the first form allocates an array instance of the type that results from deleting each of the individual expressions from the expression list. 2 For example, the array creation expression new int[10,20] produces an array instance of type int[,], and the array creation expression new int[10][,] produces an array of type int[][,]. 3 Each expression in the expression list must be of type int, uint, long, or ulong, or of a type that can be implicitly converted to one or more of these types. 4 The value of each expression determines the length of the corresponding dimension in the newly allocated array instance. 5 Since the length of an array dimension must be nonnegative, it is a compile-time error to have a constant expression with a negative value, in the expression list. Paragraph 31 Except in an unsafe context (§25.1), the layout of arrays is unspecified. Paragraph 41 If an array creation expression of the first form includes an array initializer, each expression in the expression list must be a constant and the rank and dimension lengths specified by the expression list must match those of the array initializer. Paragraph 51 In an array creation expression of the second form, the rank of the specified array type must match that of the array initializer. 2 The individual dimension lengths are inferred from the number of elements in each of the corresponding nesting levels of the array initializer. 3 Thus, the expression
new int[,] {{0, 1}, {2, 3}, {4, 5}}  
exactly corresponds to
new int[3, 2] {{0, 1}, {2, 3}, {4, 5}}  
Paragraph 61 Array initializers are described further in §19.6. Paragraph 71 The result of evaluating an array creation expression is classified as a value, namely a reference to the newly allocated array instance. 2 The run-time processing of an array creation expression consists of the following steps: Paragraph 81 An array creation expression permits instantiation of an array with elements of an array type, but the elements of such an array must be manually initialized. [Example: For example, the statement
int[][] a = new int[100][];  
creates a single-dimensional array with 100 elements of type int[]. The initial value of each element is null. end example]
2 It is not possible for the same array creation expression to also instantiate the sub-arrays, and the statement
int[][] a = new int[100][5];    // Error  
results in a compile-time error.
3 Instantiation of the sub-arrays must instead be performed manually, as in
int[][] a = new int[100][];  
for (int i = 0; i < 100; i++) a[i] = new int[5];  
Paragraph 91 When an array of arrays has a "rectangular" shape, that is when the sub-arrays are all of the same length, it is more efficient to use a multi-dimensional array. 2 In the example above, instantiation of the array of arrays creates 101 objects-one outer array and 100 sub-arrays. 3 In contrast,
int[,] = new int[100, 5];  
creates only a single object, a two-dimensional array, and accomplishes the allocation in a single statement.



14.5.10.3 Delegate creation expressions Paragraph 11
A delegate-creation-expression is used to create a new instance of a delegate-type. delegate-creation-expression : new delegate-type ( expression ) Paragraph 21 The argument of a delegate creation expression must be a method group (§14.1) or a value of a delegate-type. 2 If the argument is a method group, it identifies the method and, for an instance method, the object for which to create a delegate. 3 If the argument is a value of a delegate-type, it identifies a delegate instance of which to create a copy. Paragraph 31 The compile-time processing of a delegate-creation-expression of the form new D(E), where D is a delegate-type and E is an expression, consists of the following steps: Paragraph 41 The run-time processing of a delegate-creation-expression of the form new D(E), where D is a delegate-type and E is an expression, consists of the following steps: Paragraph 51 The method and object to which a delegate refers are determined when the delegate is instantiated and then remain constant for the entire lifetime of the delegate. 2 In other words, it is not possible to change the target method or object of a delegate once it has been created. [Note: Remember, when two delegates are combined or one is removed from another, a new delegate results; no existing delegate has its content changed. end note] Paragraph 61 It is not possible to create a delegate that refers to a property, indexer, user-defined operator, instance constructor, destructor, or static constructor. [Example: As described above, when a delegate is created from a method group, the formal parameter list and return type of the delegate determine which of the overloaded methods to select. In the example
delegate double DoubleFunc(double x);  
class A  
{  
   DoubleFunc f = new DoubleFunc(Square);  
   static float Square(float x) {  
      return x * x;  
   }  
   static double Square(double x) {  
      return x * x;  
   }  
}  
the A.f field is initialized with a delegate that refers to the second Square method because that method exactly matches the formal parameter list and return type of DoubleFunc. Had the second Square method not been present, a compile-time error would have occurred. end example]



14.5.11 The typeof operator Paragraph 11
The typeof operator is used to obtain the System.Type object for a type. typeof-expression : typeof ( type ) typeof ( void ) Paragraph 21 The first form of typeof-expression consists of a typeof keyword followed by a parenthesized type. 2 The result of an expression of this form is the System.Type object for the indicated type. 3 There is only one System.Type object for any given type. [Note: This means that for type T, typeof(T) == typeof(T) is always true. end note] Paragraph 31 The second form of typeof-expression consists of a typeof keyword followed by a parenthesized void keyword. 2 The result of an expression of this form is the System.Type object that represents the absence of a type. 3 The type object returned by typeof(void) is distinct from the type object returned for any type. [Note: This special type object is useful in class libraries that allow reflection onto methods in the language, where those methods wish to have a way to represent the return type of any method, including void methods, with an instance of System.Type. end note] [Example: The example
using System;  
class Test  
{  
   static void Main() {  
      Type[] t = {  
         typeof(int),  
         typeof(System.Int32),  
         typeof(string),  
         typeof(double[]),  
      typeof(void)   };  
      for (int i = 0; i < t.Length; i++) {  
         Console.WriteLine(t[i].FullName);  
      }  
   }  
}  
produces the following output:
System.Int32  
System.Int32  
System.String  
System.Double[]  
System.Void  
Note that int and System.Int32 are the same type. end example]


14.5.12 The checked and unchecked operators Paragraph 11
The checked and unchecked operators are used to control the overflow checking context for integral-type arithmetic operations and conversions. checked-expression : checked ( expression ) unchecked-expression : unchecked ( expression ) Paragraph 21 The checked operator evaluates the contained expression in a checked context, and the unchecked operator evaluates the contained expression in an unchecked context. 2 A checked-expression or unchecked-expression corresponds exactly to a parenthesized-expression (§14.5.3), except that the contained expression is evaluated in the given overflow checking context. Paragraph 31 The overflow checking context can also be controlled through the checked and unchecked statements (§15.11). Paragraph 41 The following operations are affected by the overflow checking context established by the checked and unchecked operators and statements: Paragraph 51 When one of the above operations produce a result that is too large to represent in the destination type, the context in which the operation is performed controls the resulting behavior: Paragraph 61 For non-constant expressions (expressions that are evaluated at run-time) that are not enclosed by any checked or unchecked operators or statements, the default overflow checking context is unchecked, unless external factors (such as compiler switches and execution environment configuration) call for checked evaluation. Paragraph 71 For constant expressions (expressions that can be fully evaluated at compile-time), the default overflow checking context is always checked. 2 Unless a constant expression is explicitly placed in an unchecked context, overflows that occur during the compile-time evaluation of the expression always cause compile-time errors. [Note: Developers may benefit if they exercise their code using checked mode (as well as unchecked mode). It also seems reasonable that, unless otherwise requested, the default overflow checking context is set to checked when debugging is enabled. end note] [Example: In the example
class Test  
{  
   static readonly int x = 1000000;  
   static readonly int y = 1000000;  
   static int F() {  
      return checked(x * y);    // Throws OverflowException  
   }  
   static int G() {  
      return unchecked(x * y);  // Returns -727379968  
   }  
   static int H() {  
      return x * y;      // Depends on default  
   }  
}  
no compile-time errors are reported since neither of the expressions can be evaluated at compile-time. At run-time, the F method throws a System.OverflowException, and the G method returns -727379968 (the lower 32 bits of the out-of-range result). The behavior of the H method depends on the default overflow checking context for the compilation, but it is either the same as F or the same as G. end example]
[Example: In the example
class Test  
{  
   const int x = 1000000;  
   const int y = 1000000;  
   static int F() {  
      return checked(x * y);    // Compile error, overflow  
   }  
   static int G() {  
      return unchecked(x * y);  // Returns -727379968  
   }  
   static int H() {  
      return x * y;      // Compile error, overflow  
   }  
}  
the overflows that occur when evaluating the constant expressions in F and H cause compile-time errors to be reported because the expressions are evaluated in a checked context. An overflow also occurs when evaluating the constant expression in G, but since the evaluation takes place in an unchecked context, the overflow is not reported. end example]
Paragraph 81 The checked and unchecked operators only affect the overflow checking context for those operations that are textually contained within the "(" and ")" tokens. 2 The operators have no effect on function members that are invoked as a result of evaluating the contained expression. [Example: In the example
class Test  
{  
   static int Multiply(int x, int y) {  
      return x * y;  
   }  
   static int F() {  
      return checked(Multiply(1000000, 1000000));  
   }  
}  
the use of checked in F does not affect the evaluation of x * y in Multiply, so x * y is evaluated in the default overflow checking context. end example]
Paragraph 91 The unchecked operator is convenient when writing constants of the signed integral types in hexadecimal notation. [Example: For example:
class Test  
{  
   public const int AllBits = unchecked((int)0xFFFFFFFF);  
   public const int HighBit = unchecked((int)0x80000000);  
}  
Both of the hexadecimal constants above are of type uint. Because the constants are outside the int range, without the unchecked operator, the casts to int would produce compile-time errors. end example] [Note: The checked and unchecked operators and statements allow programmers to control certain aspects of some numeric calculations. However, the behavior of some numeric operators depends on their operands' data types. For example, multiplying two decimals always results in an exception on overflow even within an explicitly unchecked construct. Similarly, multiplying two floats never results in an exception on overflow even within an explicitly checked construct. In addition, other operators are never affected by the mode of checking, whether default or explicit. As a service to programmers, it is recommended that the compiler issue a warning when there is an arithmetic expression within an explicitly checked or unchecked context (by operator or statement) that cannot possibly be affected by the specified mode of checking. Since such a warning is not required, the compiler has flexibility in determining the circumstances that merit the issuance of such warnings. end note]


14.6 Unary expressions
unary-expression : primary-expression + unary-expression - unary-expression ! unary-expression ~ unary-expression * unary-expression & unary-expression pre-increment-expression pre-decrement-expression cast-expression


14.6.1 Unary plus operator Paragraph 11
For an operation of the form +x, unary operator overload resolution (§14.2.3) is applied to select a specific operator implementation. 2 The operand is converted to the parameter type of the selected operator, and the type of the result is the return type of the operator. 3 The predefined unary plus operators are:
int operator +(int x);  
uint operator +(uint x);  
long operator +(long x);  
ulong operator +(ulong x);  
float operator +(float x);  
double operator +(double x);  
decimal operator +(decimal x);  
Paragraph 21 For each of these operators, the result is simply the value of the operand.


14.6.2 Unary minus operator Paragraph 11
For an operation of the form -x, unary operator overload resolution (§14.2.3) is applied to select a specific operator implementation. 2 The operand is converted to the parameter type of the selected operator, and the type of the result is the return type of the operator. 3 The predefined negation operators are: Paragraph 21 The result is computed by subtracting x from zero. 2 In a checked context, if the value of x is the maximum negative int or long, a System.OverflowException is thrown. 3 In an unchecked context, if the value of x is the maximum negative int or long, the result is that same value and the overflow is not reported. 4 If the operand of the negation operator is of type uint, it is converted to type long, and the type of the result is long. 5 An exception is the rule that permits the int value −2147483648 (−231) to be written as a decimal integer literal (§9.4.4.2). 6 If the operand of the negation operator is of type ulong, a compile-time error occurs. 7 An exception is the rule that permits the long value −9223372036854775808 (−263) to be written as a decimal integer literal (§9.4.4.2). Paragraph 31 The result is the value of x with its sign inverted. 2 If x is NaN, the result is also NaN. Paragraph 41 The result is computed by subtracting x from zero. 2 Decimal negation is equivalent to using the unary minus operator of type System.Decimal.


14.6.3 Logical negation operator Paragraph 11
For an operation of the form !x, unary operator overload resolution (§14.2.3) is applied to select a specific operator implementation. 2 The operand is converted to the parameter type of the selected operator, and the type of the result is the return type of the operator. 3 Only one predefined logical negation operator exists:
bool operator !(bool x);  
Paragraph 21 This operator computes the logical negation of the operand: If the operand is true, the result is false. 2 If the operand is false, the result is true.


14.6.4 Bitwise complement operator Paragraph 11
For an operation of the form ~x, unary operator overload resolution (§14.2.3) is applied to select a specific operator implementation. 2 The operand is converted to the parameter type of the selected operator, and the type of the result is the return type of the operator. 3 The predefined bitwise complement operators are:
int operator ~(int x);  
uint operator ~(uint x);  
long operator ~(long x);  
ulong operator ~(ulong x);  
Paragraph 21 For each of these operators, the result of the operation is the bitwise complement of x. Paragraph 31 Every enumeration type E implicitly provides the following bitwise complement operator:
E operator ~(E x);  
Paragraph 41 The result of evaluating ~x, where x is an expression of an enumeration type E with an underlying type U, is exactly the same as evaluating (E)(~(U)x).


14.6.5 Prefix increment and decrement operators
pre-increment-expression : ++ unary-expression pre-decrement-expression : -- unary-expression Paragraph 11 The operand of a prefix increment or decrement operation must be an expression classified as a variable, a property access, or an indexer access. 2 The result of the operation is a value of the same type as the operand. Paragraph 21 If the operand of a prefix increment or decrement operation is a property or indexer access, the property or indexer must have both a get and a set accessor. 2 If this is not the case, a compile-time error occurs. Paragraph 31 Unary operator overload resolution (§14.2.3) is applied to select a specific operator implementation. 2 Predefined ++ and --operators exist for the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, and any enum type. 3 The predefined ++ operators return the value produced by adding 1 to the operand, and the predefined --operators return the value produced by subtracting 1 from the operand. Paragraph 41 The run-time processing of a prefix increment or decrement operation of the form ++x or --x consists of the following steps: Paragraph 51 The ++ and --operators also support postfix notation (§14.5.9). 2 The result of x++ or x--is the value of x before the operation, whereas the result of ++x or --x is the value of x after the operation. 3 In either case, x itself has the same value after the operation. Paragraph 61 An operator ++ or operator --implementation can be invoked using either postfix or prefix notation. 2 It is not possible to have separate operator implementations for the two notations.


14.6.6 Cast expressions Paragraph 11
A cast-expression is used to explicitly convert an expression to a given type. cast-expression : ( type ) unary-expression Paragraph 21 A cast-expression of the form (T)E, where T is a type and E is a unary-expression, performs an explicit conversion (§13.2) of the value of E to type T. 2 If no explicit conversion exists from the type of E to T, a compile-time error occurs. 3 Otherwise, the result is the value produced by the explicit conversion. 4 The result is always classified as a value, even if E denotes a variable. Paragraph 31 The grammar for a cast-expression leads to certain syntactic ambiguities. 2 For example, the expression (x)-y could either be interpreted as a cast-expression (a cast of -y to type x) or as an additive-expression combined with a parenthesized-expression (which computes the value x -y). Paragraph 41 To resolve cast-expression ambiguities, the following rule exists: A sequence of one or more tokens (§9.4) enclosed in parentheses is considered the start of a cast-expression only if at least one of the following are true: [Note: The above rule means that only if the construct is unambiguously a cast-expression is it considered a cast-expression. end note] Paragraph 51 The term "correct grammar" above means only that the sequence of tokens must conform to the particular grammatical production. 2 It specifically does not consider the actual meaning of any constituent identifiers. 3 For example, if x and y are identifiers, then x.y is correct grammar for a type, even if x.y doesn't actually denote a type. [Note: From the disambiguation rule, it follows that, if x and y are identifiers, (x)y, (x)(y), and (x)(-y) are cast-expressions, but (x)-y is not, even if x identifies a type. However, if x is a keyword that identifies a predefined type (such as int), then all four forms are cast-expressions (because such a keyword could not possibly be an expression by itself). end note]


14.7 Arithmetic operators Paragraph 11
The *, /, %, +, and -operators are called the arithmetic operators. multiplicative-expression : unary-expression multiplicative-expression * unary-expression multiplicative-expression / unary-expression multiplicative-expression % unary-expression additive-expression : multiplicative-expression additive-expression + multiplicative-expression additive-expression - multiplicative-expression


14.7.1 Multiplication operator Paragraph 11
For an operation of the form x * y, binary operator overload resolution (§14.2.4) is applied to select a specific operator implementation. 2 The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator. Paragraph 21 The predefined multiplication operators are listed below. 2 The operators all compute the product of x and y.


14.7.2 Division operator Paragraph 11
For an operation of the form x / y, binary operator overload resolution (§14.2.4) is applied to select a specific operator implementation. 2 The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator. Paragraph 21 The predefined division operators are listed below. 2 The operators all compute the quotient of x and y.


14.7.3 Remainder operator Paragraph 11
For an operation of the form x % y, binary operator overload resolution (§14.2.4) is applied to select a specific operator implementation. 2 The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator. Paragraph 21 The predefined remainder operators are listed below. 2 The operators all compute the remainder of the division between x and y.


14.7.4 Addition operator Paragraph 11
For an operation of the form x + y, binary operator overload resolution (§14.2.4) is applied to select a specific operator implementation. 2 The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator. Paragraph 21 The predefined addition operators are listed below. 2 For numeric and enumeration types, the predefined addition operators compute the sum of the two operands. 3 When one or both operands are of type string, the predefined addition operators concatenate the string representation of the operands.


14.7.5 Subtraction operator Paragraph 11
For an operation of the form x -y, binary operator overload resolution (§14.2.4) is applied to select a specific operator implementation. 2 The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator. Paragraph 21 The predefined subtraction operators are listed below. 2 The operators all subtract y from x.


14.8 Shift operators Paragraph 11
The << and >> operators are used to perform bit shifting operations. shift-expression : additive-expression shift-expression << additive-expression shift-expression >> additive-expression Paragraph 21 For an operation of the form x << count or x >> count, binary operator overload resolution (§14.2.4) is applied to select a specific operator implementation. 2 The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator. Paragraph 31 When declaring an overloaded shift operator, the type of the first operand must always be the class or struct containing the operator declaration, and the type of the second operand must always be int. Paragraph 41 The predefined shift operators are listed below. Paragraph 51 For the predefined operators, the number of bits to shift is computed as follows: Paragraph 61 If the resulting shift count is zero, the shift operators simply return the value of x. Paragraph 71 Shift operations never cause overflows and produce the same results in checked and unchecked contexts. Paragraph 81 When the left operand of the >> operator is of a signed integral type, the operator performs an arithmetic shift right wherein the value of the most significant bit (the sign bit) of the operand is propagated to the high-order empty bit positions. 2 When the left operand of the >> operator is of an unsigned integral type, the operator performs a logical shift right wherein high-order empty bit positions are always set to zero. 3 To perform the opposite operation of that inferred from the operand type, explicit casts can be used. 4 For example, if x is a variable of type int, the operation unchecked((int)((uint)x >> y)) performs a logical shift right of x.


14.9 Relational and type-testing operators Paragraph 11
The ==, !=, <, >, <=, >=, is and as operators are called the relational and type-testing operators. relational-expression : shift-expression relational-expression < shift-expression relational-expression > shift-expression relational-expression <= shift-expression relational-expression >= shift-expression relational-expression is type relational-expression as type equality-expression : relational-expression equality-expression == relational-expression equality-expression != relational-expression Paragraph 21 The is operator is described in §14.9.9 and the as operator is described in §14.9.10. Paragraph 31 The ==, !=, <, >, <= and >= operators are comparison operators. 2 For an operation of the form x op y, where op is a comparison operator, overload resolution (§14.2.4) is applied to select a specific operator implementation. 3 The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator. Paragraph 41 The predefined comparison operators are described in the following sections. 2 All predefined comparison operators return a result of type bool, as described in the following table.
Operation Result
x == y true if x is equal to y, false otherwise
x != y true if x is not equal to y, false otherwise
x < y true if x is less than y, false otherwise
x > y true if x is greater than y, false otherwise
x <= y true if x is less than or equal to y, false otherwise
x >= y true if x is greater than or equal to y, false otherwise



14.9.1 Integer comparison operators Paragraph 11
The predefined integer comparison operators are:
bool operator ==(int x, int y);  
bool operator ==(uint x, uint y);  
bool operator ==(long x, long y);  
bool operator ==(ulong x, ulong y);  
bool operator !=(int x, int y);  
bool operator !=(uint x, uint y);  
bool operator !=(long x, long y);  
bool operator !=(ulong x, ulong y);  
bool operator <(int x, int y);  
bool operator <(uint x, uint y);  
bool operator <(long x, long y);  
bool operator <(ulong x, ulong y);  
bool operator >(int x, int y);  
bool operator >(uint x, uint y);  
bool operator >(long x, long y);  
bool operator >(ulong x, ulong y);  
bool operator <=(int x, int y);  
bool operator <=(uint x, uint y);  
bool operator <=(long x, long y);  
bool operator <=(ulong x, ulong y);  
bool operator >=(int x, int y);  
bool operator >=(uint x, uint y);  
bool operator >=(long x, long y);  
bool operator >=(ulong x, ulong y);  
Paragraph 21 Each of these operators compares the numeric values of the two integer operands and returns a bool value that indicates whether the particular relation is true or false.


14.9.2 Floating-point comparison operators Paragraph 11
The predefined floating-point comparison operators are:
bool operator ==(float x, float y);  
bool operator ==(double x, double y);  
bool operator !=(float x, float y);  
bool operator !=(double x, double y);  
bool operator <(float x, float y);  
bool operator <(double x, double y);  
bool operator >(float x, float y);  
bool operator >(double x, double y);  
bool operator <=(float x, float y);  
bool operator <=(double x, double y);  
bool operator >=(float x, float y);  
bool operator >=(double x, double y);  
Paragraph 21 The operators compare the operands according to the rules of the IEEE 754 standard:


14.9.3 Decimal comparison operators Paragraph 11
The predefined decimal comparison operators are:
bool operator ==(decimal x, decimal y);  
bool operator !=(decimal x, decimal y);  
bool operator <(decimal x, decimal y);  
bool operator >(decimal x, decimal y);  
bool operator <=(decimal x, decimal y);  
bool operator >=(decimal x, decimal y);  
Paragraph 21 Each of these operators compares the numeric values of the two decimal operands and returns a bool value that indicates whether the particular relation is true or false. 2 Each decimal comparison is equivalent to using the corresponding relational or equality operator of type System.Decimal.


14.9.4 Boolean equality operators Paragraph 11
The predefined boolean equality operators are:
bool operator ==(bool x, bool y);  
bool operator !=(bool x, bool y);  
Paragraph 21 The result of == is true if both x and y are true or if both x and y are false. 2 Otherwise, the result is false. Paragraph 31 The result of != is false if both x and y are true or if both x and y are false. 2 Otherwise, the result is true. 3 When the operands are of type bool, the != operator produces the same result as the ^ operator.


14.9.5 Enumeration comparison operators Paragraph 11
Every enumeration type implicitly provides the following predefined comparison operators:
bool operator ==(E x, E y);  
bool operator !=(E x, E y);  
bool operator <(E x, E y);  
bool operator >(E x, E y);  
bool operator <=(E x, E y);  
bool operator >=(E x, E y);  
Paragraph 21 The result of evaluating x op y, where x and y are expressions of an enumeration type E with an underlying type U, and op is one of the comparison operators, is exactly the same as evaluating ((U)x) op ((U)y). 2 In other words, the enumeration type comparison operators simply compare the underlying integral values of the two operands.


14.9.6 Reference type equality operators Paragraph 11
The predefined reference type equality operators are:
bool operator ==(object x, object y);  
bool operator !=(object x, object y);  
Paragraph 21 The operators return the result of comparing the two references for equality or non-equality. Paragraph 31 Since the predefined reference type equality operators accept operands of type object, they apply to all types that do not declare applicable operator == and operator != members. 2 Conversely, any applicable user-defined equality operators effectively hide the predefined reference type equality operators. Paragraph 41 The predefined reference type equality operators require the operands to be reference-type values or the value null; furthermore, they require that a standard implicit conversion (§13.3.1) exists from the type of either operand to the type of the other operand. 2 Unless both of these conditions are true, a compile-time error occurs. [Note: Notable implications of these rules are: Paragraph 51 For an operation of the form x == y or x != y, if any applicable operator == or operator != exists, the operator overload resolution (§14.2.4) rules will select that operator instead of the predefined reference type equality operator. 2 However, it is always possible to select the predefined reference type equality operator by explicitly casting one or both of the operands to type object. [Example: The example
using System;  
class Test  
{  
   static void Main() {  
      string s = "Test";  
      string t = string.Copy(s);  
      Console.WriteLine(s == t);  
      Console.WriteLine((object)s == t);  
      Console.WriteLine(s == (object)t);  
      Console.WriteLine((object)s == (object)t);  
   }  
}  
produces the output
True  
False  
False  
False  
The s and t variables refer to two distinct string instances containing the same characters. The first comparison outputs True because the predefined string equality operator (§14.9.7) is selected when both operands are of type string. The remaining comparisons all output False because the predefined reference type equality operator is selected when one or both of the operands are of type object. Note that the above technique is not meaningful for value types. The example
class Test  
{  
   static void Main() {  
      int i = 123;  
      int j = 123;  
      System.Console.WriteLine((object)i == (object)j);  
   }  
}  
outputs False because the casts create references to two separate instances of boxed int values. end example]



14.9.7 String equality operators Paragraph 11
The predefined string equality operators are: :
bool operator ==(string x, string y);  
bool operator !=(string x, string y);  
Paragraph 21 Two string values are considered equal when one of the following is true: Paragraph 31 The string equality operators compare string values rather than string references. 2 When two separate string instances contain the exact same sequence of characters, the values of the strings are equal, but the references are different. [Note: As described in §14.9.6, the reference type equality operators can be used to compare string references instead of string values. end note]


14.9.8 Delegate equality operators Paragraph 11
Every delegate type implicitly provides the following predefined comparison operators: :
bool operator ==(System.Delegate x, System.Delegate y);  
bool operator !=(System.Delegate x, System.Delegate y);  
Paragraph 21 Two delegate instances are considered equal as follows: Paragraph 31 Note that delegates of different types can be considered equal by the above definition, as long as they have the same return type and parameter types.


14.9.9 The is operator Paragraph 11
The is operator is used to dynamically check if the run-time type of an object is compatible with a given type. 2 The result of the operation e is T, where e is an expression and T is a type, is a boolean value indicating whether e can successfully be converted to type T by a reference conversion, a boxing conversion, or an unboxing conversion. 3 The operation is evaluated as follows: Paragraph 21 Note that the is operator only considers reference conversions, boxing conversions, and unboxing conversions. 2 Other conversions, such as user defined conversions, are not considered by the is operator.


14.9.10 The as operator Paragraph 11
The as operator is used to explicitly convert a value to a given reference type using a reference conversion or a boxing conversion. 2 Unlike a cast expression (§14.6.6), the as operator never throws an exception. 3 Instead, if the indicated conversion is not possible, the resulting value is null. Paragraph 21 In an operation of the form e as T, e must be an expression and T must be a reference type. 2 The type of the result is T, and the result is always classified as a value. 3 The operation is evaluated as follows: Paragraph 31 Note that the as operator only performs reference conversions and boxing conversions. 2 Other conversions, such as user defined conversions, are not possible with the as operator and should instead be performed using cast expressions.


14.10 Logical operators Paragraph 11
The &, ^, and | operators are called the logical operators. and-expression : equality-expression and-expression & equality-expression exclusive-or-expression : and-expression exclusive-or-expression ^ and-expression inclusive-or-expression : exclusive-or-expression inclusive-or-expression | exclusive-or-expression Paragraph 21 For an operation of the form x op y, where op is one of the logical operators, overload resolution (§14.2.4) is applied to select a specific operator implementation. 2 The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator. Paragraph 31 The predefined logical operators are described in the following sections.


14.10.1 Integer logical operators Paragraph 11
The predefined integer logical operators are:
int operator &(int x, int y);  
uint operator &(uint x, uint y);  
long operator &(long x, long y);  
ulong operator &(ulong x, ulong y);  
int operator |(int x, int y);  
uint operator |(uint x, uint y);  
long operator |(long x, long y);  
ulong operator |(ulong x, ulong y);  
int operator ^(int x, int y);  
uint operator ^(uint x, uint y);  
long operator ^(long x, long y);  
ulong operator ^(ulong x, ulong y);  
Paragraph 21 The & operator computes the bitwise logical AND of the two operands, the | operator computes the bitwise logical OR of the two operands, and the ^ operator computes the bitwise logical exclusive OR of the two operands. 2 No overflows are possible from these operations.


14.10.2 Enumeration logical operators Paragraph 11
Every enumeration type E implicitly provides the following predefined logical operators:
E operator &(E x, E y);  
E operator |(E x, E y);  
E operator ^(E x, E y);  
Paragraph 21 The result of evaluating x op y, where x and y are expressions of an enumeration type E with an underlying type U, and op is one of the logical operators, is exactly the same as evaluating (E)((U)x op (U)y). 2 In other words, the enumeration type logical operators simply perform the logical operation on the underlying type of the two operands.


14.10.3 Boolean logical operators Paragraph 11
The predefined boolean logical operators are:
bool operator &(bool x, bool y);  
bool operator |(bool x, bool y);  
bool operator ^(bool x, bool y);  
Paragraph 21 The result of x & y is true if both x and y are true. 2 Otherwise, the result is false. Paragraph 31 The result of x | y is true if either x or y is true. 2 Otherwise, the result is false. Paragraph 41 The result of x ^ y is true if x is true and y is false, or x is false and y is true. 2 Otherwise, the result is false. 3 When the operands are of type bool, the ^ operator computes the same result as the != operator.


14.11 Conditional logical operators Paragraph 11
The && and || operators are called the conditional logical operators. 2 They are also called the "short-circuiting" logical operators. conditional-and-expression : inclusive-or-expression conditional-and-expression && inclusive-or-expression conditional-or-expression : conditional-and-expression conditional-or-expression || conditional-and-expression Paragraph 21 The && and || operators are conditional versions of the & and | operators: Paragraph 31 An operation of the form x && y or x || y is processed by applying overload resolution (§14.2.4) as if the operation was written x & y or x | y. 2 Then, Paragraph 41 It is not possible to directly overload the conditional logical operators. 2 However, because the conditional logical operators are evaluated in terms of the regular logical operators, overloads of the regular logical operators are, with certain restrictions, also considered overloads of the conditional logical operators. 3 This is described further in §14.11.2.


14.11.1 Boolean conditional logical operators Paragraph 11
When the operands of && or || are of type bool, or when the operands are of types that do not define an applicable operator & or operator |, but do define implicit conversions to bool, the operation is processed as follows:


14.11.2 User-defined conditional logical operators Paragraph 11
When the operands of && or || are of types that declare an applicable user-defined operator & or operator |, both of the following must be true, where T is the type in which the selected operator is declared: Paragraph 21 A compile-time error occurs if either of these requirements is not satisfied. 2 Otherwise, the && or || operation is evaluated by combining the user-defined operator true or operator false with the selected user-defined operator: Paragraph 31 In either of these operations, the expression given by x is only evaluated once, and the expression given by y is either not evaluated or evaluated exactly once. Paragraph 41 For an example of a type that implements operator true and operator false, see §18.4.2.


14.12 Conditional operator Paragraph 11
The ?: operator is called the conditional operator. 2 It is at times also called the ternary operator. conditional-expression : conditional-or-expression conditional-or-expression ? expression : expression Paragraph 21 A conditional expression of the form b ? x : y first evaluates the condition b. 2 Then, if b is true, x is evaluated and becomes the result of the operation. 3 Otherwise, y is evaluated and becomes the result of the operation. 4 A conditional expression never evaluates both x and y. Paragraph 31 The conditional operator is right-associative, meaning that operations are grouped from right to left. 2 For example, an expression of the form a ? b : c ? d : e is evaluated as a ? b : (c ? d : e). Paragraph 41 The first operand of the ?: operator must be an expression of a type that can be implicitly converted to bool, or an expression of a type that implements operator true. 2 If neither of these requirements is satisfied, a compile-time error occurs. Paragraph 51 The second and third operands of the ?: operator control the type of the conditional expression. 2 Let X and Y be the types of the second and third operands. 3 Then, Paragraph 61 The run-time processing of a conditional expression of the form b ? x : y consists of the following steps:


14.13 Assignment operators Paragraph 11
The assignment operators assign a new value to a variable, a property, event, or an indexer element. assignment : unary-expression assignment-operator expression assignment-operator : one of = += -= *= /= %= &= |= ^= <<= >>= Paragraph 21 The left operand of an assignment must be an expression classified as a variable, a property access, an indexer access, or an event access. Paragraph 31 The = operator is called the simple assignment operator. 2 It assigns the value of the right operand to the variable, property, or indexer element given by the left operand. 3 The left operand of the simple assignment operator may not be an event access (except as described in §17.7.1). 4 The simple assignment operator is described in §14.13.1. Paragraph 41 The operators formed by prefixing a binary operator with an = character are called the compound assignment operators. 2 These operators perform the indicated operation on the two operands, and then assign the resulting value to the variable, property, or indexer element given by the left operand. 3 The compound assignment operators are described in §14.13.2. Paragraph 51 The += and -= operators with an event access expression as the left operand are called the event assignment operators. 2 No other assignment operator is valid with an event access as the left operand. 3 The event assignment operators are described in §14.13.3. Paragraph 61 The assignment operators are right-associative, meaning that operations are grouped from right to left. 2 For example, an expression of the form a = b = c is evaluated as a = (b = c).


14.13.1 Simple assignment Paragraph 11
The = operator is called the simple assignment operator. 2 In a simple assignment, the right operand must be an expression of a type that is implicitly convertible to the type of the left operand. 3 The operation assigns the value of the right operand to the variable, property, or indexer element given by the left operand. Paragraph 21 The result of a simple assignment expression is the value assigned to the left operand. 2 The result has the same type as the left operand and is always classified as a value. Paragraph 31 If the left operand is a property or indexer access, the property or indexer must have a set accessor. 2 If this is not the case, a compile-time error occurs. Paragraph 41 The run-time processing of a simple assignment of the form x = y consists of the following steps: [Note: The array covariance rules (§19.5) permit a value of an array type A[] to be a reference to an instance of an array type B[], provided an implicit reference conversion exists from B to A. Because of these rules, assignment to an array element of a reference-type requires a run-time check to ensure that the value being assigned is compatible with the array instance. In the example
string[] sa = new string[10];  
object[] oa = sa;  
oa[0] = null;      // Ok  
oa[1] = "Hello";     // Ok  
oa[2] = new ArrayList();  // ArrayTypeMismatchException  
the last assignment causes a System.ArrayTypeMismatchException to be thrown because an instance of ArrayList cannot be stored in an element of a string[]. end note]
Paragraph 51 When a property or indexer declared in a struct-type is the target of an assignment, the instance expression associated with the property or indexer access must be classified as a variable. 2 If the instance expression is classified as a value, a compile-time error occurs. [Note: Because of §14.5.4, the same rule also applies to fields. end note] [Example: Given the declarations:
struct Point  
{  
   int x, y;  
   public Point(int x, int y) {  
      this.x = x;  
      this.y = y;  
   }  
   public int X {  
      get { return x; }  
      set { x = value; }  
   }  
   public int Y {  
      get { return y; }  
      set { y = value; }  
   }  
}  
struct Rectangle  
{  
   Point a, b;  
   public Rectangle(Point a, Point b) {  
      this.a = a;  
      this.b = b;  
   }  
   public Point A {  
      get { return a; }  
      set { a = value; }  
   }  
   public Point B {  
      get { return b; }  
      set { b = value; }  
   }  
}  
in the example
Point p = new Point();  
p.X = 100;  
p.Y = 100;  
Rectangle r = new Rectangle();  
r.A = new Point(10, 10);  
r.B = p;  
the assignments to p.X, p.Y, r.A, and r.B are permitted because p and r are variables. However, in the example
Rectangle r = new Rectangle();  
r.A.X = 10;  
r.A.Y = 10;  
r.B.X = 100;  
r.B.Y = 100;  
the assignments are all invalid, since r.A and r.B are not variables. end example]



14.13.2 Compound assignment Paragraph 11
An operation of the form x op= y is processed by applying binary operator overload resolution (§14.2.4) as if the operation was written x op y. 2 Then, Paragraph 21 The term "evaluated only once" means that in the evaluation of x op y, the results of any constituent expressions of x are temporarily saved and then reused when performing the assignment to x. [Example: For example, in the assignment A()[B()] += C(), where A is a method returning int[], and B and C are methods returning int, the methods are invoked only once, in the order A, B, C. end example] Paragraph 31 When the left operand of a compound assignment is a property access or indexer access, the property or indexer must have both a get accessor and a set accessor. 2 If this is not the case, a compile-time error occurs. Paragraph 41 The second rule above permits x op= y to be evaluated as x = (T)(x op y) in certain contexts. 2 The rule exists such that the predefined operators can be used as compound operators when the left operand is of type sbyte, byte, short, ushort, or char. 3 Even when both arguments are of one of those types, the predefined operators produce a result of type int, as described in §14.2.6.2. 4 Thus, without a cast it would not be possible to assign the result to the left operand. Paragraph 51 The intuitive effect of the rule for predefined operators is simply that x op= y is permitted if both of x op y and x = y are permitted. [Example: In the example
byte b = 0;  
char ch = '\0';  
int i = 0;  
b += 1;        // Ok  
b += 1000;      // Error, b = 1000 not permitted  
b += i;        // Error, b = i not permitted  
b += (byte)i;    // Ok  
ch += 1;       // Error, ch = 1 not permitted  
ch += (char)1;   // Ok  
the intuitive reason for each error is that a corresponding simple assignment would also have been an error. end example]



14.13.3 Event assignment Paragraph 11
If the left operand of a += or -= operator is classified as an event access, then the expression is evaluated as follows: Paragraph 21 An event assignment expression does not yield a value. 2 Thus, an event assignment expression is valid only in the context of a statement-expression (§15.6).


14.14 Expression Paragraph 11
An expression is either a conditional-expression or an assignment. expression : conditional-expression assignment


14.15 Constant expressions Paragraph 11
A constant-expression is an expression that can be fully evaluated at compile-time. constant-expression : expression Paragraph 21 The type of a constant expression can be one of the following: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, string, any enumeration type, or the null type. 2 The following constructs are permitted in constant expressions: Paragraph 31 Whenever an expression is of one of the types listed above and contains only the constructs listed above, the expression is evaluated at compile-time. 2 This is true even if the expression is a sub-expression of a larger expression that contains non-constant constructs. Paragraph 41 The compile-time evaluation of constant expressions uses the same rules as run-time evaluation of non-constant expressions, except that where run-time evaluation would have thrown an exception, compile-time evaluation causes a compile-time error to occur. Paragraph 51 Unless a constant expression is explicitly placed in an unchecked context, overflows that occur in integral-type arithmetic operations and conversions during the compile-time evaluation of the expression always cause compile-time errors (§14.5.12). Paragraph 61 Constant expressions occur in the contexts listed below. 2 In these contexts, a compile-time error occurs if an expression cannot be fully evaluated at compile-time. Paragraph 71 An implicit constant expression conversion (§13.1.6) permits a constant expression of type int to be converted to sbyte, byte, short, ushort, uint, or ulong, provided the value of the constant expression is within the range of the destination type.


14.16 Boolean expressions Paragraph 11
A boolean-expression is an expression that yields a result of type bool. boolean-expression : expression Paragraph 21 The controlling conditional expression of an if-statement (§15.7.1), while-statement (§15.8.1), do-statement (§15.8.2), or for-statement (§15.8.3) is a boolean-expression. 2 The controlling conditional expression of the ?: operator (§14.12) follows the same rules as a boolean-expression, but for reasons of operator precedence is classified as a conditional-or-expression. Paragraph 31 A boolean-expression is required to be of a type that can be implicitly converted to bool or of a type that implements operator true. [Note: As required by §17.9.1, any type that implements operator true must also implement operator false. end note] 2 If neither requirement is satisfied, a compile-time error occurs. Paragraph 41 When a boolean expression is of a type that cannot be implicitly converted to bool but does implement operator true, then following evaluation of the expression, the operator true implementation provided by that type is invoked to produce a bool value. [Note: The DBBool struct type in §18.4.2 provides an example of a type that implements operator true and operator false. end note]


15 Statements Paragraph 11
C# provides a variety of statements. [Note: Most of these statements will be familiar to developers who have programmed in C and C++. end note] statement : labeled-statement declaration-statement embedded-statement embedded-statement : block empty-statement expression-statement selection-statement iteration-statement jump-statement try-statement checked-statement unchecked-statement lock-statement using-statement Paragraph 21 The embedded-statement nonterminal is used for statements that appear within other statements. 2 The use of embedded-statement rather than statement excludes the use of declaration statements and labeled statements in these contexts. [Example: The code
void F(bool b) {  
   if (b)  
   int i = 44;  
}  
results in a compile-time error because an if statement requires an embedded-statement rather than a statement for its if branch. If this code were permitted, then the variable i would be declared, but it could never be used. (Note, however, that by placing i's declaration in a block, the example is valid.) end example]



15.1 End points and reachability Paragraph 11
Every statement has an end point. 2 In intuitive terms, the end point of a statement is the location that immediately follows the statement. 3 The execution rules for composite statements (statements that contain embedded statements) specify the action that is taken when control reaches the end point of an embedded statement. 4 For example, when control reaches the end point of a statement in a block, control is transferred to the next statement in the block. Paragraph 21 If a statement can possibly be reached by execution, the statement is said to be reachable. 2 Conversely, if there is no possibility that a statement will be executed, the statement is said to be unreachable. [Example: In the example
void F() {  
   Console.WriteLine("reachable");  
   goto Label;  
   Console.WriteLine("unreachable");  
   Label:  
   Console.WriteLine("reachable");  
}  
the second invocation of Console.WriteLine is unreachable because there is no possibility that the statement will be executed. end example]
Paragraph 31 A warning is reported if the compiler determines that a statement is unreachable. 2 It is specifically not an error for a statement to be unreachable. [Note: To determine whether a particular statement or end point is reachable, the compiler performs flow analysis according to the reachability rules defined for each statement. The flow analysis takes into account the values of constant expressions (§14.15) that control the behavior of statements, but the possible values of non-constant expressions are not considered. In other words, for purposes of control flow analysis, a non-constant expression of a given type is considered to have any possible value of that type. In the example
void F() {  
   const int i = 1;  
   if (i == 2) Console.WriteLine("unreachable");  
}  
the boolean expression of the if statement is a constant expression because both operands of the == operator are constants. As the constant expression is evaluated at compile-time, producing the value false, the Console.WriteLine invocation is considered unreachable. However, if i is changed to be a local variable
void F() {  
   int i = 1;  
   if (i == 2) Console.WriteLine("reachable");  
}  
the Console.WriteLine invocation is considered reachable, even though, in reality, it will never be executed. end note]
Paragraph 41 The block of a function member is always considered reachable. 2 By successively evaluating the reachability rules of each statement in a block, the reachability of any given statement can be determined. [Example: In the example
void F(int x) {  
   Console.WriteLine("start");  
   if (x < 0) Console.WriteLine("negative");  
}  
the reachability of the second Console.WriteLine is determined as follows:
Paragraph 51 There are two situations in which it is a compile-time error for the end point of a statement to be reachable:


15.2 Blocks Paragraph 11
A block permits multiple statements to be written in contexts where a single statement is allowed. block : { statement-listopt } Paragraph 21 A block consists of an optional statement-list (§15.2.1), enclosed in braces. 2 If the statement list is omitted, the block is said to be empty. Paragraph 31 A block may contain declaration statements (§15.5). 2 The scope of a local variable or constant declared in a block is the block. Paragraph 41 Within a block, the meaning of a name used in an expression context must always be the same (§14.5.2.1). Paragraph 51 A block is executed as follows: Paragraph 61 The statement list of a block is reachable if the block itself is reachable. Paragraph 71 The end point of a block is reachable if the block is empty or if the end point of the statement list is reachable.


15.2.1 Statement lists Paragraph 11
A statement list consists of one or more statements written in sequence. 2 Statement lists occur in blocks (§15.2) and in switch-blocks (§15.7.2). statement-list : statement statement-list statement Paragraph 21 A statement list is executed by transferring control to the first statement. 2 When and if control reaches the end point of a statement, control is transferred to the next statement. 3 When and if control reaches the end point of the last statement, control is transferred to the end point of the statement list. Paragraph 31 A statement in a statement list is reachable if at least one of the following is true: Paragraph 41 The end point of a statement list is reachable if the end point of the last statement in the list is reachable.


15.3 The empty statement Paragraph 11
An empty-statement does nothing. empty-statement : ; Paragraph 21 An empty statement is used when there are no operations to perform in a context where a statement is required. Paragraph 31 Execution of an empty statement simply transfers control to the end point of the statement. 2 Thus, the end point of an empty statement is reachable if the empty statement is reachable. [Example: An empty statement can be used when writing a while statement with a null body:
bool ProcessMessage() {...}  
void ProcessMessages() {  
   while (ProcessMessage())  
   ;  
}  
Also, an empty statement can be used to declare a label just before the closing "}" of a block:
void F() {  
   ...  
   if (done) goto exit;  
   ...  
   exit: ;  
}  
end example]



15.4 Labeled statements Paragraph 11
A labeled-statement permits a statement to be prefixed by a label. 2 Labeled statements are permitted in blocks, but are not permitted as embedded statements. labeled-statement : identifier : statement Paragraph 21 A labeled statement declares a label with the name given by the identifier. 2 The scope of a label is the whole block in which the label is declared, including any nested blocks. 3 It is a compile-time error for two labels with the same name to have overlapping scopes. Paragraph 31 A label can be referenced from goto statements (§15.9.3) within the scope of the label. [Note: This means that goto statements can transfer control within blocks and out of blocks, but never into blocks. end note] Paragraph 41 Labels have their own declaration space and do not interfere with other identifiers. [Example: The example
int F(int x) {  
   if (x >= 0) goto x;  
   x = -x;  
   x: return x;  
}  
is valid and uses the name x as both a parameter and a label. end example]
Paragraph 51 Execution of a labeled statement corresponds exactly to execution of the statement following the label. Paragraph 61 In addition to the reachability provided by normal flow of control, a labeled statement is reachable if the label is referenced by a reachable goto statement. 2 (Exception: If a goto statement is inside a try that includes a finally block, and the labeled statement is outside the try, and the end point of the finally block is unreachable, then the labeled statement is not reachable from that goto statement.)


15.5 Declaration statements Paragraph 11
A declaration-statement declares a local variable or constant. 2 Declaration statements are permitted in blocks, but are not permitted as embedded statements. declaration-statement : local-variable-declaration ; local-constant-declaration ;


15.5.1 Local variable declarations Paragraph 11
A local-variable-declaration declares one or more local variables. local-variable-declaration : type local-variable-declarators local-variable-declarators : local-variable-declarator local-variable-declarators , local-variable-declarator local-variable-declarator : identifier identifier = local-variable-initializer local-variable-initializer : expression array-initializer Paragraph 21 The type of a local-variable-declaration specifies the type of the variables introduced by the declaration. Paragraph 31 The type is followed by a list of local-variable-declarators, each of which introduces a new variable. 2 A local-variable-declarator consists of an identifier that names the variable, optionally followed by an "=" token and a local-variable-initializer that gives the initial value of the variable. Paragraph 41 The value of a local variable is obtained in an expression using a simple-name (§14.5.2), and the value of a local variable is modified using an assignment (§14.13). 2 A local variable must be definitely assigned (§12.3) at each location where its value is obtained. Paragraph 51 The scope of a local variable declared in a local-variable-declaration is the block in which the declaration occurs. 2 It is an error to refer to a local variable in a textual position that precedes the local-variable-declarator of the local variable. 3 Within the scope of a local variable, it is a compile-time error to declare another local variable or constant with the same name. Paragraph 61 A local variable declaration that declares multiple variables is equivalent to multiple declarations of single variables with the same type. 2 Furthermore, a variable initializer in a local variable declaration corresponds exactly to an assignment statement that is inserted immediately after the declaration. [Example: The example
void F() {  
   int x = 1, y, z = x * 2;  
}  
corresponds exactly to
void F() {  
   int x; x = 1;  
   int y;  
   int z; z = x * 2;  
}  
end example]



15.5.2 Local constant declarations Paragraph 11
A local-constant-declaration declares one or more local constants. local-constant-declaration : const type constant-declarators constant-declarators : constant-declarator constant-declarators , constant-declarator constant-declarator : identifier = constant-expression Paragraph 21 The type of a local-constant-declaration specifies the type of the constants introduced by the declaration. 2 The type is followed by a list of constant-declarators, each of which introduces a new constant. 3 A constant-declarator consists of an identifier that names the constant, followed by an "=" token, followed by a constant-expression (§14.15) that gives the value of the constant. Paragraph 31 The type and constant-expression of a local constant declaration must follow the same rules as those of a constant member declaration (§17.3). Paragraph 41 The value of a local constant is obtained in an expression using a simple-name (§14.5.2). Paragraph 51 The scope of a local constant is the block in which the declaration occurs. 2 It is an error to refer to a local constant in a textual position that precedes its constant-declarator. 3 Within the scope of a local constant, it is a compile-time error to declare another local variable or constant with the same name. Paragraph 61 A local constant declaration that declares multiple constants is equivalent to multiple declarations of single constants with the same type.


15.6 Expression statements Paragraph 11
An expression-statement evaluates a given expression. 2 The value computed by the expression, if any, is discarded. expression-statement : statement-expression ; statement-expression : invocation-expression object-creation-expression assignment post-increment-expression post-decrement-expression pre-increment-expression pre-decrement-expression Paragraph 21 Not all expressions are permitted as statements. [Note: In particular, expressions such as x + y and x == 1, that merely compute a value (which will be discarded), are not permitted as statements. end note] Paragraph 31 Execution of an expression statement evaluates the contained expression and then transfers control to the end point of the expression statement. 2 The end point of an expression-statement is reachable if that expression-statement is reachable.


15.7 Selection statements Paragraph 11
Selection statements select one of a number of possible statements for execution based on the value of some expression. selection-statement : if-statement switch-statement


15.7.1 The if statement Paragraph 11
The if statement selects a statement for execution based on the value of a boolean expression. if-statement : if ( boolean-expression ) embedded-statement if ( boolean-expression ) embedded-statement else embedded-statement boolean-expression : expression Paragraph 21 An else part is associated with the lexically nearest preceding if that is allowed by the syntax. [Example: Thus, an if statement of the form
if (x) if (y) F(); else G();  
is equivalent to
if (x) {  
   if (y) {  
      F();  
   }  
   else {  
      G();  
   }  
}  
end example]
Paragraph 31 An if statement is executed as follows: Paragraph 41 The first embedded statement of an if statement is reachable if the if statement is reachable and the boolean expression does not have the constant value false. Paragraph 51 The second embedded statement of an if statement, if present, is reachable if the if statement is reachable and the boolean expression does not have the constant value true. Paragraph 61 The end point of an if statement is reachable if the end point of at least one of its embedded statements is reachable. 2 In addition, the end point of an if statement with no else part is reachable if the if statement is reachable and the boolean expression does not have the constant value true.


15.7.2 The switch statement Paragraph 11
The switch statement selects for execution a statement list having an associated switch label that corresponds to the value of the switch expression. switch-statement : switch ( expression ) switch-block switch-block : { switch-sectionsopt } switch-sections : switch-section switch-sections switch-section switch-section : switch-labels statement-list switch-labels : switch-label switch-labels switch-label switch-label : case constant-expression : default : Paragraph 21 A switch-statement consists of the keyword switch, followed by a parenthesized expression (called the switch expression), followed by a switch-block. 2 The switch-block consists of zero or more switch-sections, enclosed in braces. 3 Each switch-section consists of one or more switch-labels followed by a statement-list (§15.2.1). Paragraph 31 The governing type of a switch statement is established by the switch expression. 2 If the type of the switch expression is sbyte, byte, short, ushort, int, uint, long, ulong, char, string, or an enum-type, then that is the governing type of the switch statement. 3 Otherwise, exactly one user-defined implicit conversion (§13.4) must exist from the type of the switch expression to one of the following possible governing types: sbyte, byte, short, ushort, int, uint, long, ulong, char, string. 4 If no such implicit conversion exists, or if more than one such implicit conversion exists, a compile-time error occurs. Paragraph 41 The constant expression of each case label must denote a value of a type that is implicitly convertible (§13.1) to the governing type of the switch statement. 2 A compile-time error occurs if two or more case labels in the same switch statement specify the same constant value. Paragraph 51 There can be at most one default label in a switch statement. Paragraph 61 A switch statement is executed as follows: Paragraph 71 If the end point of the statement list of a switch section is reachable, a compile-time error occurs. 2 This is known as the "no fall through" rule. [Example: The example
switch (i) {  
   case 0:  
   CaseZero();  
   break;  
   case 1:  
   CaseOne();  
   break;  
   default:  
   CaseOthers();  
   break;  
}  
is valid because no switch section has a reachable end point. Unlike C and C++, execution of a switch section is not permitted to "fall through" to the next switch section, and the example
switch (i) {  
   case 0:  
   CaseZero();  
   case 1:  
   CaseZeroOrOne();  
   default:  
   CaseAny();  
}  
results in a compile-time error. When execution of a switch section is to be followed by execution of another switch section, an explicit goto case or goto default statement must be used:
switch (i) {  
   case 0:  
   CaseZero();  
   goto case 1;  
   case 1:  
   CaseZeroOrOne();  
   goto default;  
   default:  
   CaseAny();  
   break;  
}  
end example]
Paragraph 81 Multiple labels are permitted in a switch-section. [Example: The example
switch (i) {  
   case 0:  
   CaseZero();  
   break;  
   case 1:  
   CaseOne();  
   break;  
   case 2:  
   default:  
   CaseTwo();  
   break;  
}  
is valid. The example does not violate the "no fall through" rule because the labels case 2: and default: are part of the same switch-section. end example]
[Note: The "no fall through" rule prevents a common class of bugs that occur in C and C++ when break statements are accidentally omitted. In addition, because of this rule, the switch sections of a switch statement can be arbitrarily rearranged without affecting the behavior of the statement. For example, the sections of the switch statement above can be reversed without affecting the behavior of the statement:
switch (i) {  
   default:  
   CaseAny();  
   break;  
   case 1:  
   CaseZeroOrOne();  
   goto default;  
   case 0:  
   CaseZero();  
   goto case 1;  
}  
end note]
[Note: The statement list of a switch section typically ends in a break, goto case, or goto default statement, but any construct that renders the end point of the statement list unreachable is permitted. For example, a while statement controlled by the boolean expression true is known to never reach its end point. Likewise, a throw or return statement always transfers control elsewhere and never reaches its end point. Thus, the following example is valid:
switch (i) {  
   case 0:  
   while (true) F();  
   case 1:  
   throw new ArgumentException();  
   case 2:  
   return;  
}  
end note]
[Example: The governing type of a switch statement may be the type string. For example:
void DoCommand(string command) {  
   switch (command.ToLower()) {  
      case "run":  
      DoRun();  
      break;  
      case "save":  
      DoSave();  
      break;  
      case "quit":  
      DoQuit();  
      break;  
      default:  
      InvalidCommand(command);  
      break;  
   }  
}  
end example]
[Note: Like the string equality operators (§14.9.7), the switch statement is case sensitive and will execute a given switch section only if the switch expression string exactly matches a case label constant. end note] Paragraph 91 When the governing type of a switch statement is string, the value null is permitted as a case label constant. Paragraph 101 The statement-lists of a switch-block may contain declaration statements (§15.5). 2 The scope of a local variable or constant declared in a switch block is the switch block. Paragraph 111 Within a switch block, the meaning of a name used in an expression context must always be the same (§14.5.2.1). Paragraph 121 The statement list of a given switch section is reachable if the switch statement is reachable and at least one of the following is true: Paragraph 131 The end point of a switch statement is reachable if at least one of the following is true:


15.8 Iteration statements Paragraph 11
Iteration statements repeatedly execute an embedded statement. iteration-statement : while-statement do-statement for-statement foreach-statement


15.8.1 The while statement Paragraph 11
The while statement conditionally executes an embedded statement zero or more times. while-statement : while ( boolean-expression ) embedded-statement Paragraph 21 A while statement is executed as follows: Paragraph 31 Within the embedded statement of a while statement, a break statement (§15.9.1) may be used to transfer control to the end point of the while statement (thus ending iteration of the embedded statement), and a continue statement (§15.9.2) may be used to transfer control to the end point of the embedded statement (thus performing another iteration of the while statement). Paragraph 41 The embedded statement of a while statement is reachable if the while statement is reachable and the boolean expression does not have the constant value false. Paragraph 51 The end point of a while statement is reachable if at least one of the following is true:


15.8.2 The do statement Paragraph 11
The do statement conditionally executes an embedded statement one or more times. do-statement : do embedded-statement while ( boolean-expression ) ; Paragraph 21 A do statement is executed as follows: Paragraph 31 Within the embedded statement of a do statement, a break statement (§15.9.1) may be used to transfer control to the end point of the do statement (thus ending iteration of the embedded statement), and a continue statement (§15.9.2) may be used to transfer control to the end point of the embedded statement (thus performing another iteration of the do statement). Paragraph 41 The embedded statement of a do statement is reachable if the do statement is reachable. Paragraph 51 The end point of a do statement is reachable if at least one of the following is true:


15.8.3 The for statement Paragraph 11
The for statement evaluates a sequence of initialization expressions and then, while a condition is true, repeatedly executes an embedded statement and evaluates a sequence of iteration expressions. for-statement : for ( for-initializeropt ; for-conditionopt ; for-iteratoropt ) embedded-statement for-initializer : local-variable-declaration statement-expression-list for-condition : boolean-expression for-iterator : statement-expression-list statement-expression-list : statement-expression statement-expression-list , statement-expression Paragraph 21 The for-initializer, if present, consists of either a local-variable-declaration (§15.5.1) or a list of statement-expressions (§15.6) separated by commas. 2 The scope of a local variable declared by a for-initializer starts at the local-variable-declarator for the variable and extends to the end of the embedded statement. 3 The scope includes the for-condition and the for-iterator. Paragraph 31 The for-condition, if present, must be a boolean-expression (§14.16). Paragraph 41 The for-iterator, if present, consists of a list of statement-expressions (§15.6) separated by commas. Paragraph 51 A for statement is executed as follows: Paragraph 61 Within the embedded statement of a for statement, a break statement (§15.9.1) may be used to transfer control to the end point of the for statement (thus ending iteration of the embedded statement), and a continue statement (§15.9.2) may be used to transfer control to the end point of the embedded statement (thus executing another iteration of the for statement). Paragraph 71 The embedded statement of a for statement is reachable if one of the following is true: Paragraph 81 The end point of a for statement is reachable if at least one of the following is true:


15.8.4 The foreach statement Paragraph 11
The foreach statement enumerates the elements of a collection, executing an embedded statement for each element of the collection. foreach-statement : foreach ( type identifier in expression ) embedded-statement Paragraph 21 The type and identifier of a foreach statement declare the iteration variable of the statement. 2 The iteration variable corresponds to a read-only local variable with a scope that extends over the embedded statement. 3 During execution of a foreach statement, the iteration variable represents the collection element for which an iteration is currently being performed. 4 A compile-time error occurs if the embedded statement attempts to modify the iteration variable (via assignment or the ++ and --operators) or pass the iteration variable as a ref or out parameter. Paragraph 31 The type of the expression of a foreach statement must be a collection type (as defined below), and an explicit conversion (§13.2) must exist from the element type of the collection to the type of the iteration variable. 2 If expression has the value null, a System.NullReferenceException is thrown. Paragraph 41 A type C is said to be a collection type if it implements the System.IEnumerable interface or implements the collection pattern by meeting all of the following criteria: Paragraph 51 A type that implements IEnumerable is also a collection type, even if it doesn't satisfy the conditions above. 2 (This is possible if it implements IEnumerable via private interface implementation.) Paragraph 61 The System.Array type (§19.1.1) is a collection type, and since all array types derive from System.Array, any array type expression is permitted in a foreach statement. 2 The order in which foreach traverses the elements of an array is as follows: For single-dimensional arrays elements are traversed in increasing index order, starting with index 0 and ending with index Length -1. 3 For multi-dimensional arrays, elements are traversed such that the indices of the rightmost dimension are increased first, then the next left dimension, and so on to the left. Paragraph 71 A foreach statement of the form:
foreach (ElementType element in collection) statement  
corresponds to one of two possible expansions:
[Note: Significant optimizations of the above are often easily available. If the type E implements System.IDisposable, then the expression (enumerator as System.IDisposable) will always be non-null and the implementation can safely substitute a simple conversion for a possibly more expensive type test. Conversely, if the type E is sealed and does not implement System.IDisposable, then the expression (enumerator as System.IDisposable) will always evaluate to null. In this case, the implementation can safely optimize away the entire finally clause. end note] 4 In either expansion, the enumerator variable is a temporary variable that is inaccessible in, and invisible to, the embedded statement, and the element variable is read-only in the embedded statement. [Example: The following example prints out each value in a two-dimensional array, in element order:
using System;  
class Test  
{  
   static void Main() {  
      double[,] values = {  
         {1.2, 2.3, 3.4, 4.5},  
         {5.6, 6.7, 7.8, 8.9}  
      };  
      
      foreach (double elementValue in values)  
      Console.Write("{0} ", elementValue);  
      Console.WriteLine();  
   }  
}  
The output produced is as follows:
1.2 2.3 3.4 4.5 5.6 6.7 7.8 8.9  
end example]



15.9 Jump statements Paragraph 11
Jump statements unconditionally transfer control. jump-statement : break-statement continue-statement goto-statement return-statement throw-statement Paragraph 21 The location to which a jump statement transfers control is called the target of the jump statement. Paragraph 31 When a jump statement occurs within a block, and the target of that jump statement is outside that block, the jump statement is said to exit the block. 2 While a jump statement may transfer control out of a block, it can never transfer control into a block. Paragraph 41 Execution of jump statements is complicated by the presence of intervening try statements. 2 In the absence of such try statements, a jump statement unconditionally transfers control from the jump statement to its target. 3 In the presence of such intervening try statements, execution is more complex. 4 If the jump statement exits one or more try blocks with associated finally blocks, control is initially transferred to the finally block of the innermost try statement. 5 When and if control reaches the end point of a finally block, control is transferred to the finally block of the next enclosing try statement. 6 This process is repeated until the finally blocks of all intervening try statements have been executed. [Example: In the example
using System;  
class Test  
{  
   static void Main() {  
      while (true) {  
         try {  
            try {  
               Console.WriteLine("Before break");  
               break;  
            }  
            finally {  
               Console.WriteLine("Innermost finally block");  
            }  
         }  
         finally {  
            Console.WriteLine("Outermost finally block");  
         }  
      }  
      Console.WriteLine("After break");  
   }  
}  
the finally blocks associated with two try statements are executed before control is transferred to the target of the jump statement.
The output produced is as follows:
Before break  
Innermost finally block  
Outermost finally block  
After break  
end example]



15.9.1 The break statement Paragraph 11
The break statement exits the nearest enclosing switch, while, do, for, or foreach statement. break-statement : break ; Paragraph 21 The target of a break statement is the end point of the nearest enclosing switch, while, do, for, or foreach statement. 2 If a break statement is not enclosed by a switch, while, do, for, or foreach statement, a compile-time error occurs. Paragraph 31 When multiple switch, while, do, for, or foreach statements are nested within each other, a break statement applies only to the innermost statement. 2 To transfer control across multiple nesting levels, a goto statement (§15.9.3) must be used. Paragraph 41 A break statement cannot exit a finally block (§15.10). 2 When a break statement occurs within a finally block, the target of the break statement must be within the same finally block; otherwise a compile-time error occurs. Paragraph 51 A break statement is executed as follows: Paragraph 61 Because a break statement unconditionally transfers control elsewhere, the end point of a break statement is never reachable.


15.9.2 The continue statement Paragraph 11
The continue statement starts a new iteration of the nearest enclosing while, do, for, or foreach statement. continue-statement : continue ; Paragraph 21 The target of a continue statement is the end point of the embedded statement of the nearest enclosing while, do, for, or foreach statement. 2 If a continue statement is not enclosed by a while, do, for, or foreach statement, a compile-time error occurs. Paragraph 31 When multiple while, do, for, or foreach statements are nested within each other, a continue statement applies only to the innermost statement. 2 To transfer control across multiple nesting levels, a goto statement (§15.9.3) must be used. Paragraph 41 A continue statement cannot exit a finally block (§15.10). 2 When a continue statement occurs within a finally block, the target of the continue statement must be within the same finally block; otherwise a compile-time error occurs. Paragraph 51 A continue statement is executed as follows: Paragraph 61 Because a continue statement unconditionally transfers control elsewhere, the end point of a continue statement is never reachable.


15.9.3 The goto statement Paragraph 11
The goto statement transfers control to a statement that is marked by a label. goto-statement : goto identifier ; goto case constant-expression ; goto default ; Paragraph 21 The target of a goto identifier statement is the labeled statement with the given label. 2 If a label with the given name does not exist in the current function member, or if the goto statement is not within the scope of the label, a compile-time error occurs. [Note: This rule permits the use of a goto statement to transfer control out of a nested scope, but not into a nested scope. In the example
using System;  
class Test  
{  
   static void Main(string[] args) {  
      string[,] table = {  
         {"red", "blue", "green"},  
         {"Monday", "Wednesday", "Friday"}  
      };  
      foreach (string str in args) {  
         int row, colm;  
         for (row = 0; row <= 1; ++row)  
         for (colm = 0; colm <= 2; ++colm)  
         if (str == table[row,colm])  
         goto done;  
         Console.WriteLine("{0} not found", str);  
         continue;  
         done:  
         Console.WriteLine("Found {0} at [{1}][{2}]", str, row, colm);  
      }  
   }  
}  
a goto statement is used to transfer control out of a nested scope. end note]
3 The target of a goto case statement is the statement list in the immediately enclosing switch statement (§15.7.2) which contains a case label with the given constant value. 4 If the goto case statement is not enclosed by a switch statement, if the constant-expression is not implicitly convertible (§13.1) to the governing type of the nearest enclosing switch statement, or if the nearest enclosing switch statement does not contain a case label with the given constant value, a compile-time error occurs. Paragraph 31 The target of a goto default statement is the statement list in the immediately enclosing switch statement (§15.7.2), which contains a default label. 2 If the goto default statement is not enclosed by a switch statement, or if the nearest enclosing switch statement does not contain a default label, a compile-time error occurs. Paragraph 41 A goto statement cannot exit a finally block (§15.10). 2 When a goto statement occurs within a finally block, the target of the goto statement must be within the same finally block, or otherwise a compile-time error occurs. Paragraph 51 A goto statement is executed as follows: Paragraph 61 Because a goto statement unconditionally transfers control elsewhere, the end point of a goto statement is never reachable.


15.9.4 The return statement Paragraph 11
The return statement returns control to the caller of the function member in which the return statement appears. return-statement : return expressionopt ; Paragraph 21 A return statement with no expression can be used only in a function member that does not compute a value; that is, a method with the return type void, the set accessor of a property or indexer, the add and remove accessors of an event, an instance constructor, static constructor, or a destructor. Paragraph 31 A return statement with an expression can only be used in a function member that computes a value, that is, a method with a non-void return type, the get accessor of a property or indexer, or a user-defined operator. 2 An implicit conversion (§13.1) must exist from the type of the expression to the return type of the containing function member. Paragraph 41 It is a compile-time error for a return statement to appear in a finally block (§15.10). Paragraph 51 A return statement is executed as follows: Paragraph 61 Because a return statement unconditionally transfers control elsewhere, the end point of a return statement is never reachable.


15.9.5 The throw statement Paragraph 11
The throw statement throws an exception. throw-statement : throw expressionopt ; Paragraph 21 A throw statement with an expression throws the value produced by evaluating the expression. 2 The expression must denote a value of the class type System.Exception or of a class type that derives from System.Exception. 3 If evaluation of the expression produces null, a System.NullReferenceException is thrown instead. Paragraph 31 A throw statement with no expression can be used only in a catch block, in which case, that statement re-throws the exception that is currently being handled by that catch block. Paragraph 41 Because a throw statement unconditionally transfers control elsewhere, the end point of a throw statement is never reachable. Paragraph 51 When an exception is thrown, control is transferred to the first catch clause in an enclosing try statement that can handle the exception. 2 The process that takes place from the point of the exception being thrown to the point of transferring control to a suitable exception handler is known as exception propagation. 3 Propagation of an exception consists of repeatedly evaluating the following steps until a catch clause that matches the exception is found. 4 In this description, the throw point is initially the location at which the exception is thrown.