- •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
C# LANGUAGE SPECIFICATION
1• Next, interface members that are hidden by class members are removed from the set. This step only has
2an effect if T is a type parameter and T has both an effective base class other than object and a non-
3empty effective interface set (§26.7). For every member S.M in the set, where S is the type in which the
4member M is declared, the following rules are applied if S is a class declaration other than object:
5o If M is a constant, field, property, event, enumeration member, or type declaration, then all members
6declared in an interface declaration are removed from the set.
7o If M is a method, then all non-method members declared in an interface declaration are removed
8from the set.
9• Finally, having removed hidden members, the result of the lookup is determined:
10o If the set consists of a single member that is not a method, then this member is the result of the
11lookup.
12o Otherwise, if the set contains only methods, then this group of methods is the result of the lookup.
13o Otherwise, the lookup is ambiguous, and a compile-time error occurs.
14For member lookups in types other than type parameters and interfaces, and member lookups in interfaces
15that are strictly single-inheritance (each interface in the inheritance chain has exactly zero or one direct base
16interface), the effect of the lookup rules is simply that derived members hide base members with the same
17name. Such single-inheritance lookups are never ambiguous. The ambiguities that can possibly arise from
18member lookups in multiple-inheritance interfaces are described in §20.2.5.
1914.3.1 Base types
20For purposes of member lookup, a type T is considered to have the following base types:
21• If T is object, then T has no base type.
22• If T is an enum-type, the base types of T are the class types System.Enum, System.ValueType, and
23object.
24• If T is a struct-type, the base types of T are the class types System.ValueType and object.
25• If T is a class-type, the base types of T are the base classes of T, including the class type object.
26• If T is an interface-type, the base types of T are the base interfaces of T and the class type object.
27• If T is an array-type, the base types of T are the class types System.Array and object.
28• If T is a delegate-type, the base types of T are the class types System.Delegate and object.
2914.4 Function members
30Function members are members that contain executable statements. Function members are always members
31of types and cannot be members of namespaces. C# defines the following categories of function members:
32• Methods
33• Properties
34• Events
35• Indexers
36• User-defined operators
37• Instance constructors
38• Static constructors
39• Destructors
152
Chapter 14 Expressions
1Except for static constructors and destructors (which cannot be invoked explicitly), the statements contained
2in function members are executed through function member invocations. The actual syntax for writing a
3function member invocation depends on the particular function member category.
4The argument list (§14.4.1) of a function member invocation provides actual values or variable references
5for the parameters of the function member.
6Invocations of methods, indexers, operators, and instance constructors employ overload resolution to
7determine which of a candidate set of function members to invoke. This process is described in §14.4.2.
8Once a particular function member has been identified at compile-time, possibly through overload
9resolution, the actual run-time process of invoking the function member is described in §14.4.3.
10[Note: The following table summarizes the processing that takes place in constructs involving the six
11categories of function members that can be explicitly invoked. In the table, e, x, y, and value indicate
12expressions classified as variables or values, T indicates an expression classified as a type, F is the simple
13name of a method, and P is the simple name of a property.
14
Construct |
Example |
Description |
|
|
|
Method |
F(x, y) |
Overload resolution is applied to select the best method F in the |
invocation |
|
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 |
P |
The get accessor of the property P in the containing class or |
access |
|
struct is invoked. A compile-time error occurs if P is write- |
|
|
only. 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 compile- |
|
|
time 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. |
|
|
|
153
C# LANGUAGE SPECIFICATION
Construct |
Example |
Description |
|
|
|
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 |
e[x, y] |
Overload resolution is applied to select the best indexer in the |
access |
|
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 |
-x |
Overload resolution is applied to select the best unary operator |
invocation |
|
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 |
new T(x, y) |
Overload resolution is applied to select the best instance |
constructor |
|
constructor in the class or struct T. The instance constructor is |
invocation |
|
invoked with the argument list (x, y). |
|
|
|
1
2end note]
314.4.1 Argument lists
4Every function member invocation includes an argument list, which provides actual values or variable
5references for the parameters of the function member. The syntax for specifying the argument list of a
6function member invocation depends on the function member category:
7• For instance constructors, methods, and delegates, the arguments are specified as an argument-list, as
8described below.
9• For properties, the argument list is empty when invoking the get accessor, and consists of the
10expression specified as the right operand of the assignment operator when invoking the set accessor.
154
Chapter 14 Expressions
1• For events, the argument list consists of the expression specified as the right operand of the += or -=
2operator.
3• For indexers, the argument list consists of the expressions specified between the square brackets in the
4indexer access. When invoking the set accessor, the argument list additionally includes the expression
5specified as the right operand of the assignment operator. [Note: The additional argument is not used for
6overload resolution, just during invocation of the set accessor. end note]
7• For user-defined operators, the argument list consists of the single operand of the unary operator or the
8two operands of the binary operator.
9The arguments of properties (§17.6), events (§17.7), and user-defined operators (§17.9) are always passed as
10value parameters (§17.5.1.1). The arguments of indexers (§17.8) are always passed as value parameters
11(§17.5.1.1) or parameter arrays (§17.5.1.4). Reference and output parameters are not supported for these
12categories of function members.
13The arguments of an instance constructor, method, or delegate invocation are specified as an argument-list:
14argument-list:
15 |
argument |
16 |
argument-list , argument |
17 |
argument: |
18 |
expression |
19 |
ref variable-reference |
20out variable-reference
21An argument-list consists of one or more arguments, separated by commas. Each argument can take one of
22the following forms:
23• An expression, indicating that the argument is passed as a value parameter (§17.5.1.1).
24• The keyword ref followed by a variable-reference (§12.3.3.27), indicating that the argument is passed
25as a reference parameter (§17.5.1.2). A variable shall be definitely assigned (§12.3) before it can be
26passed as a reference parameter.
27• The keyword out followed by a variable-reference (§12.3.3.27), indicating that the argument is passed
28as an output parameter (§17.5.1.3). A variable is considered definitely assigned (§12.3) following a
29function member invocation in which the variable is passed as an output parameter.
30Passing a volatile field (§17.4.3) as a reference parameter or output parameter causes a warning, since the
31field may not be treated as volatile by the invoked method.
32During the run-time processing of a function member invocation (§14.4.3), the expressions or variable
33references of an argument list are evaluated in order, from left to right, as follows:
34• For a value parameter, the argument expression is evaluated and an implicit conversion (§13.1) to the
35corresponding parameter type is performed. The resulting value becomes the initial value of the value
36parameter in the function member invocation.
37• For a reference or output parameter, the variable reference is evaluated and the resulting storage location
38becomes the storage location represented by the parameter in the function member invocation. If the
39variable reference given as a reference or output parameter is an array element of a reference-type, a
40run-time check is performed to ensure that the element type of the array is identical to the type of the
41parameter. If this check fails, a System.ArrayTypeMismatchException is thrown.
42Methods, indexers, and instance constructors can declare their right-most parameter to be a parameter array
43(§17.5.1.4). Such function members are invoked either in their normal form or in their expanded form
44depending on which is applicable (§14.4.2.1):
45• When a function member with a parameter array is invoked in its normal form, the argument given for
46the parameter array shall be a single expression of a type that is implicitly convertible (§13.1) to the
47parameter array type. In this case, the parameter array acts precisely like a value parameter.
155
C# LANGUAGE SPECIFICATION
1• When a function member with a parameter array is invoked in its expanded form, the invocation shall
2specify zero or more arguments for the parameter array, where each argument is an expression of a type
3that is implicitly convertible (§13.1) to the element type of the parameter array. In this case, the
4invocation creates an instance of the parameter array type with a length corresponding to the number of
5arguments, initializes the elements of the array instance with the given argument values, and uses the
6newly created array instance as the actual argument.
7The expressions of an argument list are always evaluated in the order they are written. [Example: Thus,
8the example
9class Test
10{
11 |
static void F(int x, int y, int z) { |
12 |
System.Console.WriteLine("x = {0}, y = {1}, z = {2}", x, y, z); |
13 |
} |
14 |
static void Main() { |
15 |
int i = 0; |
16 |
F(i++, i++, i++); |
17}
18}
19produces the output
20x = 0, y = 1, z = 2
21end example]
22The array covariance rules (§19.5) permit a value of an array type A[] to be a reference to an instance of an
23array type B[], provided an implicit reference conversion exists from B to A. Because of these rules, when
24an array element of a reference-type is passed as a reference or output parameter, a run-time check is
25required to ensure that the actual element type of the array is identical to that of the parameter. [Example: In
26the following code
27class Test
28{
29 |
static void |
F(ref object x) {…} |
|
30 |
static void |
Main() { |
|
31 |
object[] a = new object[10]; |
||
32 |
object[] b = new string[10]; |
||
33 |
F(ref a[0]); |
// Ok |
|
34 |
F(ref b[1]); |
// ArrayTypeMismatchException |
|
35}
36}
37the second invocation of F causes a System.ArrayTypeMismatchException to be thrown because the
38actual element type of b is string and not object. end example]
39When a function member with a parameter array is invoked in its expanded form, the invocation is
40processed exactly as if an array creation expression with an array initializer (§14.5.10.2) was inserted around
41the expanded parameters. [Example: Given the declaration
42void F(int x, int y, params object[] args);
43the following invocations of the expanded form of the method
44F(10, 20);
45F(10, 20, 30, 40);
46F(10, 20, 1, "hello", 3.0);
47correspond exactly to
48F(10, 20, new object[] {});
49F(10, 20, new object[] {30, 40});
50F(10, 20, new object[] {1, "hello", 3.0});
51In particular, note that an empty array is created when there are zero arguments given for the parameter
52array. end example]
156
