
- •Language Specification
- •Version 4.0
- •1. Introduction 1
- •2. Lexical structure 37
- •3. Basic concepts 59
- •4. Types 83
- •5. Variables 99
- •6. Conversions 115
- •7. Expressions 137
- •8. Statements 239
- •9. Namespaces 268
- •10. Classes 279
- •11. Structs 376
- •12. Arrays 389
- •12.1 Array types 389
- •13. Interfaces 395
- •18. Unsafe code 443
- •1.Introduction
- •1.1Hello world
- •1.2Program structure
- •1.3Types and variables
- •1.4Expressions
- •1.5Statements
- •1.6Classes and objects
- •1.6.1Members
- •1.6.2Accessibility
- •1.6.3Type parameters
- •1.6.4Base classes
- •1.6.5Fields
- •1.6.6Methods
- •1.6.6.1Parameters
- •1.6.6.2Method body and local variables
- •1.6.6.3Static and instance methods
- •1.6.6.4Virtual, override, and abstract methods
- •1.6.6.5Method overloading
- •1.6.7Other function members
- •1.6.7.1Constructors
- •1.6.7.2Properties
- •1.6.7.3Indexers
- •1.6.7.4Events
- •1.6.7.5Operators
- •1.6.7.6Destructors
- •1.7Structs
- •1.8Arrays
- •1.9Interfaces
- •1.10Enums
- •1.11Delegates
- •1.12Attributes
- •2.Lexical structure
- •2.1Programs
- •2.2Grammars
- •2.2.1Grammar notation
- •2.2.2Lexical grammar
- •2.2.3Syntactic grammar
- •2.3Lexical analysis
- •2.3.1Line terminators
- •2.3.2Comments
- •2.3.3White space
- •2.4Tokens
- •2.4.1Unicode character escape sequences
- •2.4.2Identifiers
- •2.4.3Keywords
- •2.4.4Literals
- •2.4.4.1Boolean literals
- •2.4.4.2Integer literals
- •2.4.4.3Real literals
- •2.4.4.4Character literals
- •2.4.4.5String literals
- •2.4.4.6The null literal
- •2.4.5Operators and punctuators
- •2.5Pre-processing directives
- •2.5.1Conditional compilation symbols
- •2.5.2Pre-processing expressions
- •2.5.3Declaration directives
- •2.5.4Conditional compilation directives
- •2.5.5Diagnostic directives
- •2.5.6Region directives
- •2.5.7Line directives
- •2.5.8Pragma directives
- •2.5.8.1Pragma warning
- •3.Basic concepts
- •3.1Application Startup
- •3.2Application termination
- •3.3Declarations
- •3.4Members
- •3.4.1Namespace members
- •3.4.2Struct members
- •3.4.3Enumeration members
- •3.4.4Class members
- •3.5.1Declared accessibility
- •3.5.2Accessibility domains
- •3.5.3Protected access for instance members
- •3.5.4Accessibility constraints
- •3.6Signatures and overloading
- •3.7Scopes
- •3.7.1Name hiding
- •3.7.1.1Hiding through nesting
- •3.7.1.2Hiding through inheritance
- •3.8Namespace and type names
- •3.8.1Fully qualified names
- •3.9Automatic memory management
- •3.10Execution order
- •4.Types
- •4.1Value types
- •4.1.1The System.ValueType type
- •4.1.2Default constructors
- •4.1.3Struct types
- •4.1.4Simple types
- •4.1.5Integral types
- •4.1.6Floating point types
- •4.1.7The decimal type
- •4.1.8The bool type
- •4.1.9Enumeration types
- •4.1.10Nullable types
- •4.2Reference types
- •4.2.1Class types
- •4.2.2The object type
- •4.2.3The dynamic type
- •4.3Boxing and unboxing
- •4.3.1Boxing conversions
- •4.3.2Unboxing conversions
- •4.4Constructed types
- •4.4.1Type arguments
- •4.4.2Open and closed types
- •4.4.3Bound and unbound types
- •4.4.4Satisfying constraints
- •4.5Type parameters
- •4.6Expression tree types
- •4.7The dynamic type
- •5.Variables
- •5.1Variable categories
- •5.1.1Static variables
- •5.1.2Instance variables
- •5.1.2.1Instance variables in classes
- •5.1.2.2Instance variables in structs
- •5.1.3Array elements
- •5.1.4Value parameters
- •5.1.5Reference parameters
- •5.1.6Output parameters
- •5.1.7Local variables
- •5.2Default values
- •5.3Definite assignment
- •5.3.1Initially assigned variables
- •Value parameters.
- •5.3.2Initially unassigned variables
- •5.3.3Precise rules for determining definite assignment
- •5.3.3.1General rules for statements
- •5.3.3.2Block statements, checked, and unchecked statements
- •5.3.3.3Expression statements
- •5.3.3.4Declaration statements
- •5.3.3.5If statements
- •5.3.3.6Switch statements
- •5.3.3.7While statements
- •5.3.3.8Do statements
- •5.3.3.9For statements
- •5.3.3.10Break, continue, and goto statements
- •5.3.3.11Throw statements
- •5.3.3.12Return statements
- •5.3.3.13Try-catch statements
- •5.3.3.14Try-finally statements
- •5.3.3.15Try-catch-finally statements
- •5.3.3.21General rules for expressions with embedded expressions
- •5.3.3.22Invocation expressions and object creation expressions
- •5.3.3.23Simple assignment expressions
- •5.3.3.24&& Expressions
- •5.3.3.25|| Expressions
- •5.3.3.26! Expressions
- •5.3.3.27?? Expressions
- •5.3.3.28?: Expressions
- •5.3.3.29Anonymous functions
- •5.4Variable references
- •5.5Atomicity of variable references
- •6.Conversions
- •6.1Implicit conversions
- •6.1.1Identity conversion
- •6.1.2Implicit numeric conversions
- •6.1.3Implicit enumeration conversions
- •6.1.4Implicit nullable conversions
- •6.1.5Null literal conversions
- •6.1.6Implicit reference conversions
- •6.1.7Boxing conversions
- •6.1.8Implicit dynamic conversions
- •6.1.9Implicit constant expression conversions
- •6.1.10Implicit conversions involving type parameters
- •6.1.11User-defined implicit conversions
- •6.1.12Anonymous function conversions and method group conversions
- •6.2Explicit conversions
- •6.2.1Explicit numeric conversions
- •6.2.2Explicit enumeration conversions
- •6.2.3Explicit nullable conversions
- •6.2.4Explicit reference conversions
- •6.2.5Unboxing conversions
- •6.2.6Explicit dynamic conversions
- •6.2.7Explicit conversions involving type parameters
- •6.2.8User-defined explicit conversions
- •6.3Standard conversions
- •6.3.1Standard implicit conversions
- •6.3.2Standard explicit conversions
- •6.4User-defined conversions
- •6.4.1Permitted user-defined conversions
- •6.4.2Lifted conversion operators
- •6.4.3Evaluation of user-defined conversions
- •6.4.4User-defined implicit conversions
- •6.4.5User-defined explicit conversions
- •6.5Anonymous function conversions
- •6.5.1Evaluation of anonymous function conversions to delegate types
- •6.5.2Evaluation of anonymous function conversions to expression tree types
- •6.5.3Implementation example
- •6.6Method group conversions
- •7.Expressions
- •7.1Expression classifications
- •7.1.1Values of expressions
- •7.2Static and Dynamic Binding
- •7.2.1Binding-time
- •7.2.2Dynamic binding
- •7.2.3Types of constituent expressions
- •7.3Operators
- •7.3.1Operator precedence and associativity
- •7.3.2Operator overloading
- •7.3.3Unary operator overload resolution
- •7.3.4Binary operator overload resolution
- •7.3.5Candidate user-defined operators
- •7.3.6Numeric promotions
- •7.3.6.1Unary numeric promotions
- •7.3.6.2Binary numeric promotions
- •7.3.7Lifted operators
- •7.4Member lookup
- •7.4.1Base types
- •7.5Function members
- •Indexers
- •Instance constructors
- •7.5.1Argument lists
- •7.5.1.1Corresponding parameters
- •7.5.1.2Run-time evaluation of argument lists
- •7.5.2Type inference
- •7.5.2.1The first phase
- •7.5.2.2The second phase
- •7.5.2.7Explicit parameter type inferences
- •7.5.2.8Exact inferences
- •7.5.2.9Lower-bound inferences
- •7.5.2.10Upper-bound inferences
- •7.5.2.11Fixing
- •7.5.2.12Inferred return type
- •7.5.2.13Type inference for conversion of method groups
- •7.5.2.14Finding the best common type of a set of expressions
- •7.5.3Overload resolution
- •7.5.3.1Applicable function member
- •7.5.3.2Better function member
- •7.5.3.3Better conversion from expression
- •7.5.3.4Better conversion from type
- •7.5.3.5Better conversion target
- •7.5.3.6Overloading in generic classes
- •7.5.4Compile-time checking of dynamic overload resolution
- •7.5.5Function member invocation
- •7.5.5.1Invocations on boxed instances
- •7.6Primary expressions
- •7.6.1Literals
- •7.6.2Simple names
- •7.6.2.1Invariant meaning in blocks
- •7.6.3Parenthesized expressions
- •7.6.4Member access
- •7.6.4.1Identical simple names and type names
- •7.6.4.2Grammar ambiguities
- •7.6.5Invocation expressions
- •7.6.5.1Method invocations
- •7.6.5.2Extension method invocations
- •7.6.5.3Delegate invocations
- •7.6.6Element access
- •7.6.6.1Array access
- •7.6.6.2Indexer access
- •7.6.7This access
- •7.6.8Base access
- •7.6.9Postfix increment and decrement operators
- •7.6.10The new operator
- •7.6.10.1Object creation expressions
- •7.6.10.2Object initializers
- •7.6.10.3Collection initializers
- •7.6.10.4Array creation expressions
- •7.6.10.5Delegate creation expressions
- •7.6.10.6Anonymous object creation expressions
- •7.6.11The typeof operator
- •7.6.12The checked and unchecked operators
- •7.6.13Default value expressions
- •7.6.14Anonymous method expressions
- •7.7Unary operators
- •7.7.1Unary plus operator
- •7.7.2Unary minus operator
- •7.7.3Logical negation operator
- •7.7.4Bitwise complement operator
- •7.7.5Prefix increment and decrement operators
- •7.7.6Cast expressions
- •7.8Arithmetic operators
- •7.8.1Multiplication operator
- •7.8.2Division operator
- •7.8.3Remainder operator
- •7.8.4Addition operator
- •7.8.5Subtraction operator
- •7.9Shift operators
- •7.10Relational and type-testing operators
- •7.10.1Integer comparison operators
- •7.10.2Floating-point comparison operators
- •7.10.3Decimal comparison operators
- •7.10.4Boolean equality operators
- •7.10.5Enumeration comparison operators
- •7.10.6Reference type equality operators
- •7.10.7String equality operators
- •7.10.8Delegate equality operators
- •7.10.9Equality operators and null
- •7.10.10The is operator
- •7.10.11The as operator
- •7.11Logical operators
- •7.11.1Integer logical operators
- •7.11.2Enumeration logical operators
- •7.11.3Boolean logical operators
- •7.11.4Nullable boolean logical operators
- •7.12Conditional logical operators
- •7.12.1Boolean conditional logical operators
- •7.12.2User-defined conditional logical operators
- •7.13The null coalescing operator
- •7.14Conditional operator
- •7.15Anonymous function expressions
- •7.15.1Anonymous function signatures
- •7.15.2Anonymous function bodies
- •7.15.3Overload resolution
- •7.15.4Anonymous functions and dynamic binding
- •7.15.5Outer variables
- •7.15.5.1Captured outer variables
- •7.15.5.2Instantiation of local variables
- •7.15.6Evaluation of anonymous function expressions
- •7.16Query expressions
- •7.16.1Ambiguities in query expressions
- •7.16.2Query expression translation
- •7.16.2.1Select and groupby clauses with continuations
- •7.16.2.2Explicit range variable types
- •7.16.2.3Degenerate query expressions
- •7.16.2.4From, let, where, join and orderby clauses
- •7.16.2.5Select clauses
- •7.16.2.6Groupby clauses
- •7.16.2.7Transparent identifiers
- •7.16.3The query expression pattern
- •7.17Assignment operators
- •7.17.1Simple assignment
- •7.17.2Compound assignment
- •7.17.3Event assignment
- •7.18Expression
- •7.19Constant expressions
- •7.20Boolean expressions
- •8.Statements
- •8.1End points and reachability
- •8.2Blocks
- •8.2.1Statement lists
- •8.3The empty statement
- •8.4Labeled statements
- •8.5Declaration statements
- •8.5.1Local variable declarations
- •8.5.2Local constant declarations
- •8.6Expression statements
- •8.7Selection statements
- •8.7.1The if statement
- •8.7.2The switch statement
- •8.8Iteration statements
- •8.8.1The while statement
- •8.8.2The do statement
- •8.8.3The for statement
- •8.8.4The foreach statement
- •8.9Jump statements
- •8.9.1The break statement
- •8.9.2The continue statement
- •8.9.3The goto statement
- •8.9.4The return statement
- •8.9.5The throw statement
- •8.10The try statement
- •8.11The checked and unchecked statements
- •8.12The lock statement
- •8.13The using statement
- •8.14The yield statement
- •9.Namespaces
- •9.1Compilation units
- •9.2Namespace declarations
- •9.3Extern aliases
- •9.4Using directives
- •9.4.1Using alias directives
- •9.4.2Using namespace directives
- •9.5Namespace members
- •9.6Type declarations
- •9.7Namespace alias qualifiers
- •9.7.1Uniqueness of aliases
- •10.Classes
- •10.1Class declarations
- •10.1.1Class modifiers
- •10.1.1.1Abstract classes
- •10.1.1.2Sealed classes
- •10.1.1.3Static classes
- •10.1.1.3.1Referencing static class types
- •10.1.2Partial modifier
- •10.1.3Type parameters
- •10.1.4Class base specification
- •10.1.4.1Base classes
- •10.1.4.2Interface implementations
- •10.1.5Type parameter constraints
- •10.1.6Class body
- •10.2Partial types
- •10.2.1Attributes
- •10.2.2Modifiers
- •10.2.3Type parameters and constraints
- •10.2.4Base class
- •10.2.5Base interfaces
- •10.2.6Members
- •10.2.7Partial methods
- •10.2.8Name binding
- •10.3Class members
- •10.3.1The instance type
- •10.3.2Members of constructed types
- •10.3.3Inheritance
- •10.3.4The new modifier
- •10.3.5Access modifiers
- •10.3.6Constituent types
- •10.3.7Static and instance members
- •10.3.8Nested types
- •10.3.8.1Fully qualified name
- •10.3.8.2Declared accessibility
- •10.3.8.3Hiding
- •10.3.8.4This access
- •10.3.8.5Access to private and protected members of the containing type
- •10.3.8.6Nested types in generic classes
- •10.3.9Reserved member names
- •10.3.9.1Member names reserved for properties
- •10.5Fields
- •10.5.1Static and instance fields
- •10.5.2Readonly fields
- •10.5.2.1Using static readonly fields for constants
- •10.5.2.2Versioning of constants and static readonly fields
- •10.5.3Volatile fields
- •10.5.4Field initialization
- •10.5.5Variable initializers
- •10.5.5.1Static field initialization
- •10.5.5.2Instance field initialization
- •10.6Methods
- •10.6.1Method parameters
- •10.6.1.1Value parameters
- •10.6.1.2Reference parameters
- •10.6.1.3Output parameters
- •10.6.1.4Parameter arrays
- •10.6.2Static and instance methods
- •10.6.3Virtual methods
- •10.6.4Override methods
- •10.6.5Sealed methods
- •10.6.6Abstract methods
- •10.6.7External methods
- •10.6.8Partial methods
- •10.6.9Extension methods
- •10.6.10Method body
- •10.6.11Method overloading
- •10.7Properties
- •10.7.1Static and instance properties
- •10.7.2Accessors
- •10.7.3Automatically implemented properties
- •10.7.4Accessibility
- •10.7.5Virtual, sealed, override, and abstract accessors
- •10.8Events
- •10.8.1Field-like events
- •10.8.2Event accessors
- •10.8.3Static and instance events
- •10.8.4Virtual, sealed, override, and abstract accessors
- •10.9Indexers
- •10.9.1Indexer overloading
- •10.10Operators
- •10.10.1Unary operators
- •10.10.2Binary operators
- •10.10.3Conversion operators
- •10.11Instance constructors
- •10.11.1Constructor initializers
- •10.11.2Instance variable initializers
- •10.11.3Constructor execution
- •10.11.4Default constructors
- •10.11.5Private constructors
- •10.11.6Optional instance constructor parameters
- •10.12Static constructors
- •10.13Destructors
- •10.14Iterators
- •10.14.4.1The MoveNext method
- •10.14.4.2The Current property
- •10.14.4.3The Dispose method
- •10.14.5Enumerable objects
- •10.14.5.1The GetEnumerator method
- •10.14.6Implementation example
- •11.Structs
- •11.1Struct declarations
- •11.1.1Struct modifiers
- •11.3Class and struct differences
- •11.3.1Value semantics
- •11.3.2Inheritance
- •11.3.3Assignment
- •11.3.4Default values
- •11.3.5Boxing and unboxing
- •11.3.6Meaning of this
- •11.3.7Field initializers
- •11.3.8Constructors
- •11.3.9Destructors
- •11.3.10Static constructors
- •11.4Struct examples
- •11.4.1Database integer type
- •11.4.2Database boolean type
- •12.Arrays
- •12.1Array types
- •12.1.1The System.Array type
- •12.1.2Arrays and the generic iList interface
- •12.2Array creation
- •12.3Array element access
- •12.4Array members
- •12.5Array covariance
- •12.6Array initializers
- •13.Interfaces
- •13.1Interface declarations
- •13.1.1Interface modifiers
- •13.1.2Partial modifier
- •13.1.3Variant type parameter lists
- •13.1.3.1Variance safety
- •13.1.3.2Variance conversion
- •13.1.4Base interfaces
- •13.1.5Interface body
- •13.2Interface members
- •13.2.1Interface methods
- •13.2.2Interface properties
- •13.2.3Interface events
- •13.2.4Interface indexers
- •13.2.5Interface member access
- •13.3Fully qualified interface member names
- •13.4Interface implementations
- •13.4.1Explicit interface member implementations
- •13.4.2Uniqueness of implemented interfaces
- •13.4.3Implementation of generic methods
- •13.4.4Interface mapping
- •13.4.5Interface implementation inheritance
- •13.4.6Interface re-implementation
- •13.4.7Abstract classes and interfaces
- •14.Enums
- •14.1Enum declarations
- •14.2Enum modifiers
- •14.3Enum members
- •14.4The System.Enum type
- •14.5Enum values and operations
- •15.Delegates
- •15.1Delegate declarations
- •15.2Delegate compatibility
- •15.3Delegate instantiation
- •15.4Delegate invocation
- •16.Exceptions
- •16.1Causes of exceptions
- •16.2The System.Exception class
- •16.3How exceptions are handled
- •16.4Common Exception Classes
- •17.Attributes
- •17.1Attribute classes
- •17.1.1Attribute usage
- •17.1.2Positional and named parameters
- •17.1.3Attribute parameter types
- •17.2Attribute specification
- •17.3Attribute instances
- •17.3.1Compilation of an attribute
- •17.3.2Run-time retrieval of an attribute instance
- •17.4Reserved attributes
- •17.4.1The AttributeUsage attribute
- •17.4.2The Conditional attribute
- •17.4.2.1Conditional methods
- •17.4.2.2Conditional attribute classes
- •17.4.3The Obsolete attribute
- •17.5Attributes for Interoperation
- •17.5.1Interoperation with com and Win32 components
- •17.5.2Interoperation with other .Net languages
- •17.5.2.1The IndexerName attribute
- •18.Unsafe code
- •18.1Unsafe contexts
- •18.2Pointer types
- •18.3Fixed and moveable variables
- •18.4Pointer conversions
- •18.4.1Pointer arrays
- •18.5Pointers in expressions
- •18.5.1Pointer indirection
- •18.5.2Pointer member access
- •18.5.3Pointer element access
- •18.5.4The address-of operator
- •18.5.5Pointer increment and decrement
- •18.5.6Pointer arithmetic
- •18.5.7Pointer comparison
- •18.5.8The sizeof operator
- •18.6The fixed statement
- •18.7Fixed size buffers
- •18.7.1Fixed size buffer declarations
- •18.7.2Fixed size buffers in expressions
- •18.7.3Definite assignment checking
- •18.8Stack allocation
- •18.9Dynamic memory allocation
- •Documentation comments
- •Introduction
- •Recommended tags
- •Processing the documentation file
- •Id string format
- •Id string examples
- •An example
- •C# source code
- •Resulting xml
- •Keywords
- •Literals
- •Operators and punctuators
- •Syntactic grammar
- •Basic concepts
- •Variables
- •Expressions
- •Statements
- •Namespaces
- •Classes
- •Structs
- •Interfaces
- •Delegates
- •Attributes
- •Grammar extensions for unsafe code
- •References
- •Copyright ó Microsoft Corporation 1999-20101998. All Rights Reserved. Please send corrections, comments, and other feedback to csharp@microsoft.Com
1.6.7.6Destructors
A 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 invoked explicitly. The destructor for an instance is invoked automatically during garbage collection.
The garbage collector is allowed wide latitude in deciding when to collect objects and run destructors. Specifically, the timing of destructor invocations is not deterministic, and destructors may be executed on any thread. For these and other reasons, classes should implement destructors only when no other solutions are feasible.
The using statement provides a better approach to object destruction.
1.7Structs
Like classes, structs are data structures that can contain data members and function members, but unlike classes, structs are value types and do not require heap allocation. A variable of a struct type directly stores the data of the struct, whereas a variable of a class type stores a reference to a dynamically allocated object. Struct types do not support user-specified inheritance, and all struct types implicitly inherit from type object.
Structs are particularly useful for small data structures that have value semantics. Complex numbers, points in a coordinate system, or key-value pairs in a dictionary are all good examples of structs. The use of structs rather than classes for small data structures can make a large difference in the number of memory allocations an application performs. For example, the following program 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); } }
An alternative is to make Point a struct.
struct Point { public int x, y;
public Point(int x, int y) { this.x = x; this.y = y; } }
Now, only one object is instantiated—the one for the array—and the Point instances are stored in-line in the array.
Struct constructors are invoked with the new operator, but that does not imply that memory is being allocated. Instead of dynamically allocating an object and returning a reference to it, a struct constructor simply returns the struct value itself (typically in a temporary location on the stack), and this value is then copied as necessary.
With classes, 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 structs, the variables each have their own copy of the data, and it is not possible for operations on one to affect the other. For example, the output produced by the following code fragment depends on whether Point is a class or a struct.
Point a = new Point(10, 10); Point b = a; a.x = 20; Console.WriteLine(b.x);
If Point is a class, the output is 20 because a and b reference the same object. If Point is a struct, the output is 10 because the assignment of a to b creates a copy of the value, and this copy is unaffected by the subsequent assignment to a.x.
The previous example highlights two of the limitations of structs. First, copying an entire struct is typically less efficient than copying an object reference, so assignment and value parameter passing can be more expensive with structs than with reference types. Second, except for ref and out parameters, it is not possible to create references to structs, which rules out their usage in a number of situations.