
- •Foreword
- •Introduction
- •Scope
- •Conformance
- •Normative references
- •Definitions
- •Notational conventions
- •Acronyms and abbreviations
- •General description
- •Language overview
- •Getting started
- •Types
- •Predefined types
- •Conversions
- •Array types
- •Type system unification
- •Variables and parameters
- •Automatic memory management
- •Expressions
- •Statements
- •Classes
- •Constants
- •Fields
- •Methods
- •Properties
- •Events
- •Operators
- •Indexers
- •Instance constructors
- •Destructors
- •Static constructors
- •Inheritance
- •Static classes
- •Partial type declarations
- •Structs
- •Interfaces
- •Delegates
- •Enums
- •Namespaces and assemblies
- •Versioning
- •Extern Aliases
- •Attributes
- •Generics
- •Why generics?
- •Creating and consuming generics
- •Multiple type parameters
- •Constraints
- •Generic methods
- •Anonymous methods
- •Iterators
- •Lexical structure
- •Programs
- •Grammars
- •Lexical grammar
- •Syntactic grammar
- •Grammar ambiguities
- •Lexical analysis
- •Line terminators
- •Comments
- •White space
- •Tokens
- •Unicode escape sequences
- •Identifiers
- •Keywords
- •Literals
- •Boolean literals
- •Integer literals
- •Real literals
- •Character literals
- •String literals
- •The null literal
- •Operators and punctuators
- •Pre-processing directives
- •Conditional compilation symbols
- •Pre-processing expressions
- •Declaration directives
- •Conditional compilation directives
- •Diagnostic directives
- •Region control
- •Line directives
- •Pragma directives
- •Basic concepts
- •Application startup
- •Application termination
- •Declarations
- •Members
- •Namespace members
- •Struct members
- •Enumeration members
- •Class members
- •Interface members
- •Array members
- •Delegate members
- •Member access
- •Declared accessibility
- •Accessibility domains
- •Protected access for instance members
- •Accessibility constraints
- •Signatures and overloading
- •Scopes
- •Name hiding
- •Hiding through nesting
- •Hiding through inheritance
- •Namespace and type names
- •Unqualified name
- •Fully qualified names
- •Automatic memory management
- •Execution order
- •Types
- •Value types
- •The System.ValueType type
- •Default constructors
- •Struct types
- •Simple types
- •Integral types
- •Floating point types
- •The decimal type
- •The bool type
- •Enumeration types
- •Reference types
- •Class types
- •The object type
- •The string type
- •Interface types
- •Array types
- •Delegate types
- •Boxing and unboxing
- •Boxing conversions
- •Unboxing conversions
- •Variables
- •Variable categories
- •Static variables
- •Instance variables
- •Instance variables in classes
- •Instance variables in structs
- •Array elements
- •Value parameters
- •Reference parameters
- •Output parameters
- •Local variables
- •Default values
- •Definite assignment
- •Initially assigned variables
- •Initially unassigned variables
- •Precise rules for determining definite assignment
- •General rules for statements
- •Block statements, checked, and unchecked statements
- •Expression statements
- •Declaration statements
- •If statements
- •Switch statements
- •While statements
- •Do statements
- •For statements
- •Break, continue, and goto statements
- •Throw statements
- •Return statements
- •Try-catch statements
- •Try-finally statements
- •Try-catch-finally statements
- •Foreach statements
- •Using statements
- •Lock statements
- •General rules for simple expressions
- •General rules for expressions with embedded expressions
- •Invocation expressions and object creation expressions
- •Simple assignment expressions
- •&& expressions
- •|| expressions
- •! expressions
- •?: expressions
- •Anonymous method expressions
- •Yield statements
- •Variable references
- •Atomicity of variable references
- •Conversions
- •Implicit conversions
- •Identity conversion
- •Implicit numeric conversions
- •Implicit enumeration conversions
- •Implicit reference conversions
- •Boxing conversions
- •Implicit type parameter conversions
- •Implicit constant expression conversions
- •User-defined implicit conversions
- •Explicit conversions
- •Explicit numeric conversions
- •Explicit enumeration conversions
- •Explicit reference conversions
- •Unboxing conversions
- •User-defined explicit conversions
- •Standard conversions
- •Standard implicit conversions
- •Standard explicit conversions
- •User-defined conversions
- •Permitted user-defined conversions
- •Evaluation of user-defined conversions
- •User-defined implicit conversions
- •User-defined explicit conversions
- •Anonymous method conversions
- •Method group conversions
- •Expressions
- •Expression classifications
- •Values of expressions
- •Operators
- •Operator precedence and associativity
- •Operator overloading
- •Unary operator overload resolution
- •Binary operator overload resolution
- •Candidate user-defined operators
- •Numeric promotions
- •Unary numeric promotions
- •Binary numeric promotions
- •Member lookup
- •Base types
- •Function members
- •Argument lists
- •Overload resolution
- •Applicable function member
- •Better function member
- •Better conversion
- •Function member invocation
- •Invocations on boxed instances
- •Primary expressions
- •Literals
- •Simple names
- •Invariant meaning in blocks
- •Parenthesized expressions
- •Member access
- •Identical simple names and type names
- •Invocation expressions
- •Method invocations
- •Delegate invocations
- •Element access
- •Array access
- •Indexer access
- •This access
- •Base access
- •Postfix increment and decrement operators
- •The new operator
- •Object creation expressions
- •Array creation expressions
- •Delegate creation expressions
- •The typeof operator
- •The checked and unchecked operators
- •Default value expression
- •Anonymous methods
- •Anonymous method signatures
- •Anonymous method blocks
- •Outer variables
- •Captured outer variables
- •Instantiation of local variables
- •Anonymous method evaluation
- •Implementation example
- •Unary expressions
- •Unary plus operator
- •Unary minus operator
- •Logical negation operator
- •Bitwise complement operator
- •Prefix increment and decrement operators
- •Cast expressions
- •Arithmetic operators
- •Multiplication operator
- •Division operator
- •Remainder operator
- •Addition operator
- •Subtraction operator
- •Shift operators
- •Relational and type-testing operators
- •Integer comparison operators
- •Floating-point comparison operators
- •Decimal comparison operators
- •Boolean equality operators
- •Enumeration comparison operators
- •Reference type equality operators
- •String equality operators
- •Delegate equality operators
- •The is operator
- •The as operator
- •Logical operators
- •Integer logical operators
- •Enumeration logical operators
- •Boolean logical operators
- •Conditional logical operators
- •Boolean conditional logical operators
- •User-defined conditional logical operators
- •Conditional operator
- •Assignment operators
- •Simple assignment
- •Compound assignment
- •Event assignment
- •Expression
- •Constant expressions
- •Boolean expressions
- •Statements
- •End points and reachability
- •Blocks
- •Statement lists
- •The empty statement
- •Labeled statements
- •Declaration statements
- •Local variable declarations
- •Local constant declarations
- •Expression statements
- •Selection statements
- •The if statement
- •The switch statement
- •Iteration statements
- •The while statement
- •The do statement
- •The for statement
- •The foreach statement
- •Jump statements
- •The break statement
- •The continue statement
- •The goto statement
- •The return statement
- •The throw statement
- •The try statement
- •The checked and unchecked statements
- •The lock statement
- •The using statement
- •The yield statement
- •Namespaces
- •Compilation units
- •Namespace declarations
- •Extern alias directives
- •Using directives
- •Using alias directives
- •Using namespace directives
- •Namespace members
- •Type declarations
- •Qualified alias member
- •Classes
- •Class declarations
- •Class modifiers
- •Abstract classes
- •Sealed classes
- •Static classes
- •Class base specification
- •Base classes
- •Interface implementations
- •Class body
- •Partial declarations
- •Class members
- •Inheritance
- •The new modifier
- •Access modifiers
- •Constituent types
- •Static and instance members
- •Nested types
- •Fully qualified name
- •Declared accessibility
- •Hiding
- •this access
- •Reserved member names
- •Member names reserved for properties
- •Member names reserved for events
- •Member names reserved for indexers
- •Member names reserved for destructors
- •Constants
- •Fields
- •Static and instance fields
- •Readonly fields
- •Using static readonly fields for constants
- •Versioning of constants and static readonly fields
- •Volatile fields
- •Field initialization
- •Variable initializers
- •Static field initialization
- •Instance field initialization
- •Methods
- •Method parameters
- •Value parameters
- •Reference parameters
- •Output parameters
- •Parameter arrays
- •Static and instance methods
- •Virtual methods
- •Override methods
- •Sealed methods
- •Abstract methods
- •External methods
- •Method body
- •Method overloading
- •Properties
- •Static and instance properties
- •Accessors
- •Virtual, sealed, override, and abstract accessors
- •Events
- •Field-like events
- •Event accessors
- •Static and instance events
- •Virtual, sealed, override, and abstract accessors
- •Indexers
- •Indexer overloading
- •Operators
- •Unary operators
- •Binary operators
- •Conversion operators
- •Instance constructors
- •Constructor initializers
- •Instance variable initializers
- •Constructor execution
- •Default constructors
- •Private constructors
- •Optional instance constructor parameters
- •Static constructors
- •Destructors
- •Structs
- •Struct declarations
- •Struct modifiers
- •Struct interfaces
- •Struct body
- •Struct members
- •Class and struct differences
- •Value semantics
- •Inheritance
- •Assignment
- •Default values
- •Boxing and unboxing
- •Meaning of this
- •Field initializers
- •Constructors
- •Destructors
- •Static constructors
- •Struct examples
- •Database integer type
- •Database boolean type
- •Arrays
- •Array types
- •The System.Array type
- •Array creation
- •Array element access
- •Array members
- •Array covariance
- •Arrays and the generic IList interface
- •Array initializers
- •Interfaces
- •Interface declarations
- •Interface modifiers
- •Base interfaces
- •Interface body
- •Interface members
- •Interface methods
- •Interface properties
- •Interface events
- •Interface indexers
- •Interface member access
- •Fully qualified interface member names
- •Interface implementations
- •Explicit interface member implementations
- •Interface mapping
- •Interface implementation inheritance
- •Interface re-implementation
- •Abstract classes and interfaces
- •Enums
- •Enum declarations
- •Enum modifiers
- •Enum members
- •The System.Enum type
- •Enum values and operations
- •Delegates
- •Delegate declarations
- •Delegate instantiation
- •Delegate invocation
- •Exceptions
- •Causes of exceptions
- •The System.Exception class
- •How exceptions are handled
- •Common Exception Classes
- •Attributes
- •Attribute classes
- •Attribute usage
- •Positional and named parameters
- •Attribute parameter types
- •Attribute specification
- •Attribute instances
- •Compilation of an attribute
- •Run-time retrieval of an attribute instance
- •Reserved attributes
- •The AttributeUsage attribute
- •The Conditional attribute
- •Conditional Methods
- •Conditional Attribute Classes
- •The Obsolete attribute
- •Unsafe code
- •Unsafe contexts
- •Pointer types
- •Fixed and moveable variables
- •Pointer conversions
- •Pointers in expressions
- •Pointer indirection
- •Pointer member access
- •Pointer element access
- •The address-of operator
- •Pointer increment and decrement
- •Pointer arithmetic
- •Pointer comparison
- •The sizeof operator
- •The fixed statement
- •Stack allocation
- •Dynamic memory allocation
- •Generics
- •Generic class declarations
- •Type parameters
- •The instance type
- •Members of generic classes
- •Static fields in generic classes
- •Static constructors in generic classes
- •Accessing protected members
- •Overloading in generic classes
- •Parameter array methods and type parameters
- •Overriding and generic classes
- •Operators in generic classes
- •Nested types in generic classes
- •Generic struct declarations
- •Generic interface declarations
- •Uniqueness of implemented interfaces
- •Explicit interface member implementations
- •Generic delegate declarations
- •Constructed types
- •Type arguments
- •Open and closed types
- •Base classes and interfaces of a constructed type
- •Members of a constructed type
- •Accessibility of a constructed type
- •Conversions
- •Using alias directives
- •Generic methods
- •Generic method signatures
- •Virtual generic methods
- •Calling generic methods
- •Inference of type arguments
- •Using a generic method with a delegate
- •Constraints
- •Satisfying constraints
- •Member lookup on type parameters
- •Type parameters and boxing
- •Conversions involving type parameters
- •Iterators
- •Iterator blocks
- •Enumerator interfaces
- •Enumerable interfaces
- •Yield type
- •This access
- •Enumerator objects
- •The MoveNext method
- •The Current property
- •The Dispose method
- •Enumerable objects
- •The GetEnumerator method
- •Implementation example
- •Lexical grammar
- •Line terminators
- •White space
- •Comments
- •Unicode character escape sequences
- •Identifiers
- •Keywords
- •Literals
- •Operators and punctuators
- •Pre-processing directives
- •Syntactic grammar
- •Basic concepts
- •Types
- •Expressions
- •Statements
- •Classes
- •Structs
- •Arrays
- •Interfaces
- •Enums
- •Delegates
- •Attributes
- •Generics
- •Grammar extensions for unsafe code
- •Undefined behavior
- •Implementation-defined behavior
- •Unspecified behavior
- •Other Issues
- •Capitalization styles
- •Pascal casing
- •Camel casing
- •All uppercase
- •Capitalization summary
- •Word choice
- •Namespaces
- •Classes
- •Interfaces
- •Enums
- •Static fields
- •Parameters
- •Methods
- •Properties
- •Events
- •Case sensitivity
- •Avoiding type name confusion
- •Documentation Comments
- •Introduction
- •Recommended tags
- •<code>
- •<example>
- •<exception>
- •<list>
- •<para>
- •<param>
- •<paramref>
- •<permission>
- •<remarks>
- •<returns>
- •<seealso>
- •<summary>
- •<value>
- •Processing the documentation file
- •ID string format
- •ID string examples
- •An example
- •C# source code
- •Resulting XML
Chapter 10 Basic concepts
110. Basic concepts
210.1 Application startup
3Application startup occurs when the execution environment calls a designated method, which is referred to
4as the application's entry point. This entry point method is always named Main, and shall have one of the
5following signatures:
6static void Main() {…}
7static void Main(string[] args) {…}
8static int Main() {…}
9static int Main(string[] args) {…}
10As shown, the entry point can optionally return an int value. This return value is used in application
11termination (§10.2).
12The entry point can optionally have one formal parameter, and this formal parameter can have any name. If
13such a parameter is declared, it shall obey the following constraints:
14• The implementation shall ensure that the value of this parameter is not null.
15• Let args be the name of the parameter. If the length of the array designated by args is greater than
16zero, the array members args[0] through args[args.Length-1], inclusive, shall refer to strings,
17called application parameters, which are given implementation-defined values by the host environment
18prior to application startup. The intent is to supply to the application information determined prior to
19application startup from elsewhere in the hosted environment. If the host environment is not capable of
20supplying strings with letters in both uppercase and lowercase, the implementation shall ensure that the
21strings are received in lowercase. [Note: On systems supporting a command line, application parameters
22correspond to what are generally known as command-line arguments. end note]
23Since C# supports method overloading, a class or struct can contain multiple definitions of some method,
24provided each has a different signature. However, within a single program, no class or struct shall contain
25more than one method called Main whose definition qualifies it to be used as an application entry point.
26Other overloaded versions of Main are permitted, however, provided they have more than one parameter, or
27their only parameter is other than type string[].
28An application can be made up of multiple classes or structs. It is possible for more than one of these classes
29or structs to contain a method called Main whose definition qualifies it to be used as an application entry
30point. In such cases, one of these Main methods shall be chosen as the entry point so that application startup
31can occur. This choice of an entry point is beyond the scope of this specification—no mechanism for
32specifying or determining an entry point is provided.
33In C#, every method shall be defined as a member of a class or struct. Ordinarily, the declared accessibility
34(§10.5.1) of a method is determined by the access modifiers (§17.2.3) specified in its declaration, and
35similarly the declared accessibility of a type is determined by the access modifiers specified in its
36declaration. In order for a given method of a given type to be callable, both the type and the member shall be
37accessible. However, the application entry point is a special case. Specifically, the execution environment
38can access the application's entry point regardless of its declared accessibility and regardless of the declared
39accessibility of its enclosing type declarations.
40The entry point method shall not be defined in a generic class declaration (§26.1) or a generic struct
41declaration (§26.2).
42In all other respects, entry point methods behave like those that are not entry points.
83
C# LANGUAGE SPECIFICATION
110.2 Application termination
2Application termination returns control to the execution environment.
3If the return type of the application’s entry point method is int, the value returned serves as the
4application's termination status code. The purpose of this code is to allow communication of success or
5failure to the execution environment.
6If the return type of the entry point method is void, reaching the right brace (}) which terminates that
7method, or executing a return statement that has no expression, results in a termination status code of 0.
8Prior to an application’s termination, destructors for all of its objects that have not yet been garbage
9collected are called, unless such cleanup has been suppressed (by a call to the library method
10GC.SuppressFinalize, for example).
1110.3 Declarations
12Declarations in a C# program define the constituent elements of the program. C# programs are organized
13using namespace declarations (§16), which can contain type declarations and nested namespace declarations.
14Type declarations (§16.6) are used to define classes (§17), structs (§18), interfaces (§20), enums (§21), and
15delegates (§22). The kinds of members permitted in a type declaration depend on the form of the type
16declaration. For instance, class declarations can contain declarations for constants (§17.3), fields (§17.4),
17methods (§17.5), properties (§17.6), events (§17.7), indexers (§17.8), operators (§17.9), instance
18constructors (§17.10), destructors (§17.12), static constructors (§17.11), and nested types.
19A declaration defines a name in the declaration space to which the declaration belongs. It is a compile-time
20error to have two or more declarations that introduce members with the same name in a declaration space,
21except in the following cases
22• Two or more namespace declarations with the same name are allowed in the same declaration space.
23Such namespace declarations are aggregated to form a single logical namespace and share a single
24declaration space.
25• Declarations in separate programs but in the same namespace declaration space are allowed to share the
26same name.
27• Two or more methods with the same name but distinct signatures are allowed in the same declaration
28space (§10.6).
29• Two or more type declarations with the same name but distinct numbers of type parameters are allowed
30in the same declaration space (§10.8.2).
31• Two or more type declarations with the partial modifier in the same declaration space may share the
32same name, same number of type parameters and same classification (class, struct or interface).
33In this case, the type declarations contribute to a single type and are themselves aggregated to form a
34single declaration space (§17.1.4).
35• A namespace declaration and one or more type declarations in the same declaration space may share the
36same name as long as the type declarations all have at least one type parameter (§10.8.2).
37It is never possible for a type declaration space to contain different kinds of members with the same name.
38[Example: A type declaration space can never contain a field and a method by the same name. end example]
39There are several different types of declaration spaces, as described in the following.
40• Within all source files of a program, namespace-member-declarations with no enclosing namespace-
41declaration are members of a single combined declaration space called the global declaration space.
42• Within all source files of a program, namespace-member-declarations within namespace-declarations
43that have the same fully qualified namespace name are members of a single combined declaration space.
84
Chapter 10 Basic concepts
1• Each compilation-unit and namespace-body has an alias declaration space. Each extern-alias-directive
2and using-alias-directive of the compilation-unit or namespace-body contributes a member to the alias
3declaration space (§16.4.1).
4• Each non-partial class, struct, or interface declaration creates a new declaration space. Each partial class,
5struct, or interface declaration contributes to a declaration space shared by all matching parts in the same
6program (§17.1.4). Names are introduced into this declaration space through the type-parameter-list and
7class-member-declarations, struct-member-declarations, or interface-member-declarations. Except for
8overloaded instance constructor declarations and static constructor declarations, a class or struct member
9declaration cannot introduce a member by the same name as the class or struct. A class, struct, or
10interface permits the declaration of overloaded methods and indexers. Furthermore, a class or struct
11permits the declaration of overloaded instance constructors, operators, and types. [Example: A class,
12struct, or interface can contain multiple method declarations with the same name, provided these method
13declarations differ in their signature (§10.6). A class or struct can contain multiple nested types with the
14same name provided the types differ in the number of type parameters. end example] Base classes do not
15contribute to the declaration space of a class, and base interfaces do not contribute to the declaration
16space of an interface. Thus, a derived class or interface is allowed to declare a member with the same
17name as an inherited member.
18• Each enumeration declaration creates a new declaration space. Names are introduced into this
19declaration space through enum-member-declarations.
20• Each block or switch-block creates a declaration space for local variables and local constants called the
21local variable declaration space. Names are introduced into this declaration space through local-
22variable-declarations and local-constant-declarations. If a block is the body of an instance constructor,
23method, or operator declaration, or a get or set accessor for an indexer declaration, the parameters
24declared in such a declaration are members of the block’s local variable declaration space. If a block is
25the body of a generic method, the type parameters declared in such a declaration are members of the
26block’s local variable declaration space. It is an error for two members of a local variable declaration
27space to have the same name. It is an error for the local variable declaration space of a block and the
28local variable declaration space of a nested block to contain elements with the same name. [Note: Thus,
29within a nested block it is not possible to declare a local variable or constant with the same name as a
30local variable or constant in an enclosing block. It is possible for two nested blocks to contain elements
31with the same name as long as neither block contains the other. end note]
32• Each block or switch-block creates a separate declaration space for labels called the label declaration
33space of the block. Names are introduced into this declaration space through labeled-statements, and the
34names are referenced through goto-statements. It is an error for the label declaration space of a block
35and the label declaration space of a nested block to contain elements with the same name. Thus, within a
36nested block it is not possible to declare a label with the same name as a label in an enclosing block.
37[Note: It is possible for two nested blocks to contain elements with the same name as long as neither
38block contains the other. end note]
39The textual order in which names are declared is generally of no significance. In particular, textual order is
40not significant for the declaration and use of namespaces, constants, methods, properties, events, indexers,
41operators, instance constructors, destructors, static constructors, and types. Declaration order is significant in
42the following ways:
43• Declaration order for field declarations and local variable declarations determines the order in which
44their initializers (if any) are executed. When there are field declarations in multiple partial type
45declarations for the same type, the order of the parts is unspecified. However, within each part the field
46initializers are executed in order.
47• Local variables and local constants shall be defined before they are used (§10.7).
48• Declaration order for enum member declarations (§21.3) is significant when constant-expression values
49are omitted.
85
C# LANGUAGE SPECIFICATION
1[Example: The declaration space of a namespace is “open ended”, and two namespace declarations with the
2same fully qualified name contribute to the same declaration space. For example
3namespace Megacorp.Data
4{
5 |
class Customer |
6 |
{ |
7 |
… |
8}
9}
10namespace Megacorp.Data
11{
12 |
class Order |
13 |
{ |
14 |
… |
15}
16}
17The two namespace declarations above contribute to the same declaration space, in this case declaring two
18classes with the fully qualified names Megacorp.Data.Customer and Megacorp.Data.Order. Because
19the two declarations contribute to the same declaration space, it would have caused a compile-time error if
20each contained a declaration of a class with the same name.
21All declarations of a partial type contribute to the same declaration space:
22partial class C
23{
24 |
int F; |
25 |
partial struct N1 {…} |
26 |
partial class N2 {…} |
27partial class N3 {…}
28}
29partial class C
30{
31 |
void F() {…} |
// Error: conflicts with |
field F |
32 |
partial class N1 {…} // Error: conflicts with |
struct N1 |
|
33 |
class N2 {…} |
// Error: conflicts with |
other N2 |
34partial class N3 {…} // Ok
35}
36The two partial declarations for C combine to form a single declaration space and a single type. The field
37named F in the first part conflicts with the method named F in the second part. The struct named N1 in the
38first part conflicts with the class named N1 in the second part. The non-partial class N2 in the second part
39conflicts with the partial class N2 in the first part. The two partial declarations for N3 combine to form a
40single type C.N3. end example]
41[Note: As specified above, the declaration space of a block cannot share names with the declaration spaces
42of any nested blocks. Thus, in the following example, the F and G methods result in a compile-time error
43because the name i is declared in the outer block and cannot be redeclared in the inner block. However, the
44H and I methods are valid since the two i’s are declared in separate non-nested blocks.
45class A
46{
47 |
void F() { |
48 |
int i = 0; |
49 |
if (true) { |
50 |
int i = 1; |
51 |
} |
52 |
} |
53 |
void G() { |
54 |
if (true) { |
55 |
int i = 0; |
56 |
} |
57 |
int i = 1; |
58 |
} |
86