- •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 11 Types
111. Types
2The types of the C# language are divided into three main categories: Value types, reference types , and type-
3parameter types.
4type:
5
6
7
value-type reference-type type-parameter
8Type parameters are part of generics, and are discussed in §26.1.1. A fourth category of types, pointers, is
9available only in unsafe code. This is discussed further in §25.2.
10Value types differ from reference types in that variables of the value types directly contain their data,
11whereas variables of the reference types store references to their data, the latter being known as objects.
12With reference types, it is possible for two variables to reference the same object, and thus possible for
13operations on one variable to affect the object referenced by the other variable. With value types, the
14variables each have their own copy of the data, and it is not possible for operations on one to affect the other.
15[Note: When a variable is a ref or out parameter, it does not have its own storage but references the
16storage of another variable. In this case, the ref or out variable is effectively an alias for another variable
17and not a distinct variable. end note]
18C#’s type system is unified such that a value of any type can be treated as an object. Every type in C#
19directly or indirectly derives from the object class type, and object is the ultimate base class of all types.
20Values of reference types are treated as objects simply by viewing the values as type object. Values of
21value types are treated as objects by performing boxing and unboxing operations (§11.3).
2211.1 Value types
23A value type is either a struct type or an enumeration type. C# provides a set of predefined struct types
24called the simple types. The simple types are identified through reserved words.
25value-type:
26 |
struct-type |
27 |
enum-type |
28 |
struct-type: |
29 |
type-name |
30 |
simple-type |
31 |
simple-type: |
32 |
numeric-type |
33bool
34numeric-type:
35 |
integral-type |
36 |
floating-point-type |
37 |
decimal |
105
|
C# LANGUAGE SPECIFICATION |
1 |
integral-type: |
2 |
sbyte |
3 |
byte |
4 |
short |
5 |
ushort |
6 |
int |
7 |
uint |
8 |
long |
9 |
ulong |
10char
11floating-point-type:
12 float
13double
14enum-type:
15 |
type-name |
16All value types implicitly inherit from class object. It is not possible for any type to derive from a value
17type, and value types are thus implicitly sealed (§17.1.1.2).
18A variable of a value type always contains a value of that type. Unlike reference types, it is not possible for
19a value of a value type to be null, or to reference an object of a more derived type.
20Assignment to a variable of a value type creates a copy of the value being assigned. This differs from
21assignment to a variable of a reference type, which copies the reference but not the object identified by the
22reference.
2311.1.1 The System.ValueType type
24All value types implicitly inherit from the class System.ValueType, which, in turn, inherits from class
25object.
26Note that System.ValueType is not itself a value-type. Rather, it is a class-type from which all value-types
27are automatically derived.
2811.1.2 Default constructors
29All value types implicitly declare a public parameterless instance constructor called the default constructor.
30The default constructor returns a zero-initialized instance known as the default value for the value type:
31• For all simple-types, the default value is the value produced by a bit pattern of all zeros:
32o For sbyte, byte, short, ushort, int, uint, long, and ulong, the default value is 0.
33o For char, the default value is '\x0000'.
34o For float, the default value is 0.0f.
35o For double, the default value is 0.0d.
36o For decimal, the default value is 0m.
37o For bool, the default value is false.
38• For an enum-type E, the default value is 0.
39• For a struct-type, the default value is the value produced by setting all value type fields to their default
40value and all reference type fields to null.
41Like any other instance constructor, the default constructor of a value type is invoked using the new
42operator. [Note: For efficiency reasons, this requirement is not intended to actually have the implementation
43generate a constructor call. For value types, the default value expression (§14.5.13) produces the same result
106
Chapter 11 Types
1as using the default constructor. end note] [Example: In the code below, variables i, j and k are all
2initialized to zero.
3class A
4{
5 |
void F() { |
6 |
int i = 0; |
7 |
int j = new int(); |
8 |
int k = default(int); |
9}
10}
11end example]
12Because every value type implicitly has a public parameterless instance constructor, it is not possible for a
13struct type to contain an explicit declaration of a parameterless constructor. A struct type is however
14permitted to declare parameterized instance constructors (§18.3.8).
1511.1.3 Struct types
16A struct type is a value type that can declare constants, fields, methods, properties, indexers, operators,
17instance constructors, static constructors, and nested types. Struct types are described in §18.
1811.1.4 Simple types
19C# provides a set of predefined struct types called the simple types. The simple types are identified through
20reserved words, but these reserved words are simply aliases for predefined struct types in the System
21namespace, as described in the table below.
22
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 |
|
|
23
24Because a simple type aliases a struct type, every simple type has members. [Example: int has the members
25declared in System.Int32 and the members inherited from System.Object, and the following
26statements are permitted:
27 |
int i = int.MaxValue; |
// System.Int32.MaxValue constant |
28 |
string s = i.ToString(); |
// System.Int32.ToString() instance method |
29 |
string t = 123.ToString(); |
// System.Int32.ToString() instance method |
30end example] The simple types differ from other struct types in that they permit certain additional
31operations:
107
C# LANGUAGE SPECIFICATION
1• Most simple types permit values to be created by writing literals (§9.4.4). [Example: 123 is a literal of
2type int and 'a' is a literal of type char. end example] C# makes no provision for literals of struct
3types in general.
4• When the operands of an expression are all simple type constants, the compiler evaluates the expression
5at compile-time. Such an expression is known as a constant-expression (§14.15). Expressions involving
6operators defined by other struct types are not considered to be constant expressions.
7• Through const declarations, it is possible to declare constants of the simple types (§17.3). It is not
8possible to have constants of other struct types, but a similar effect is provided by static readonly
9fields.
10• Conversions involving simple types can participate in evaluation of conversion operators defined by
11other struct types, but a user-defined conversion operator can never participate in evaluation of another
12user-defined conversion operator (§13.4.2).
1311.1.5 Integral types
14C# supports nine integral types: sbyte, byte, short, ushort, int, uint, long, ulong, and char. The
15integral types have the following sizes and ranges of values:
16• The sbyte type represents signed 8-bit integers with values from –128 to 127, inclusive.
17• The byte type represents unsigned 8-bit integers with values from 0 to 255, inclusive.
18• The short type represents signed 16-bit integers with values from –32768 to 32767, inclusive.
19• The ushort type represents unsigned 16-bit integers with values from 0 to 65535, inclusive.
20• The int type represents signed 32-bit integers with values from –2147483648 to 2147483647,
21inclusive.
22• The uint type represents unsigned 32-bit integers with values from 0 to 4294967295, inclusive.
23• The long type represents signed 64-bit integers with values from –9223372036854775808 to
249223372036854775807, inclusive.
25• The ulong type represents unsigned 64-bit integers with values from 0 to 18446744073709551615,
26inclusive.
27• The char type represents unsigned 16-bit integers with values from 0 to 65535, inclusive. The set of
28possible values for the char type corresponds to the Unicode character set. [Note: Although char has
29the same representation as ushort, not all operations permitted on one type are permitted on the other.
30end note]
31The integral-type unary and binary operators always operate with signed 32-bit precision, unsigned 32-bit
32precision, signed 64-bit precision, or unsigned 64-bit precision, as detailed in clause §14.
33The char type is classified as an integral type, but it differs from the other integral types in two ways:
34• There are no implicit conversions from other types to the char type. In particular, even though the
35sbyte, byte, and ushort types have ranges of values that are fully representable using the char type,
36implicit conversions from sbyte, byte, or ushort to char do not exist.
37• Constants of the char type shall be written as character-literals or as integer-literals in combination
38with a cast to type char. [Example: (char)10 is the same as '\x000A'. end example]
39The checked and unchecked operators and statements are used to control overflow checking for integral-
40type arithmetic operations and conversions (§14.5.12). In a checked context, an overflow produces a
41compile-time error or causes a System.OverflowException to be thrown. In an unchecked context,
42overflows are ignored and any high-order bits that do not fit in the destination type are discarded.
108
