
- •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.1Hello world
The “Hello, World” program is traditionally used to introduce a programming language. Here it is in C#:
using System;
class Hello { static void Main() { Console.WriteLine("Hello, World"); } }
C# source files typically have the file extension .cs. Assuming that the “Hello, World” program is stored in the file hello.cs, the program can be compiled with the Microsoft C# compiler using the command line
csc hello.cs
which produces an executable assembly named hello.exe. The output produced by this application when it is run is
Hello, World
The “Hello, World” program starts with a using directive that references the System namespace. Namespaces provide a hierarchical means of organizing C# programs and libraries. Namespaces contain types and other namespaces—for example, the System namespace contains a number of types, such as the Console class referenced in the program, and a number of other namespaces, such as IO and Collections. A using directive that references a given namespace enables unqualified use of the types that are members of that namespace. Because of the using directive, the program can use Console.WriteLine as shorthand for System.Console.WriteLine.
The Hello class declared by the “Hello, World” program has a single member, the method named Main. The Main method is declared with the static modifier. While instance methods can reference a particular enclosing object instance using the keyword this, static methods operate without reference to a particular object. By convention, a static method named Main serves as the entry point of a program.
The output of the program is produced by the WriteLine method of the Console class in the System namespace. This class is provided by the .NET Framework class libraries, which, by default, are automatically referenced by the Microsoft C# compiler. Note that C# itself does not have a separate runtime library. Instead, the .NET Framework is the runtime library of C#.
1.2Program structure
The key organizational concepts in C# are programs, namespaces, types, members, and assemblies. C# programs consist of one or more source files. Programs declare types, which contain members and can be organized into namespaces. Classes and interfaces are examples of types. Fields, methods, properties, and events are examples of members. When C# programs are compiled, they are physically packaged into assemblies. Assemblies typically have the file extension .exe or .dll, depending on whether they implement applications or libraries.
The example
using System;
namespace Acme.Collections { public class Stack { Entry top;
public void Push(object data) { top = new Entry(top, data); }
public object Pop() { if (top == null) throw new InvalidOperationException(); object result = top.data; top = top.next; return result; }
class Entry { public Entry next; public object data;
public Entry(Entry next, object data) { this.next = next; this.data = data; } } } }
declares a class named Stack in a namespace called Acme.Collections. The fully qualified name of this class is Acme.Collections.Stack. The class contains several members: a field named top, two methods named Push and Pop, and a nested class named Entry. The Entry class further contains three members: a field named next, a field named data, and a constructor. Assuming that the source code of the example is stored in the file acme.cs, the command line
csc /t:library acme.cs
compiles the example as a library (code without a Main entry point) and produces an assembly named acme.dll.
Assemblies contain executable code in the form of Intermediate Language (IL) instructions, and symbolic information in the form of metadata. Before it is executed, the IL code in an assembly is automatically converted to processor-specific code by the Just-In-Time (JIT) compiler of .NET Common Language Runtime.
Because an assembly is a self-describing unit of functionality containing both code and metadata, there is no need for #include directives and header files in C#. The public types and members contained in a particular assembly are made available in a C# program simply by referencing that assembly when compiling the program. For example, this program uses the Acme.Collections.Stack class from the acme.dll assembly:
using System; using Acme.Collections;
class Test { static void Main() { Stack s = new Stack(); s.Push(1); s.Push(10); s.Push(100); Console.WriteLine(s.Pop()); Console.WriteLine(s.Pop()); Console.WriteLine(s.Pop()); } }
If the program is stored in the file test.cs, when test.cs is compiled, the acme.dll assembly can be referenced using the compiler’s /r option:
csc /r:acme.dll test.cs
This creates an executable assembly named test.exe, which, when run, produces the output:
100 10 1
C# permits the source text of a program to be stored in several source files. When a multi-file C# program is compiled, all of the source files are processed together, and the source files can freely reference each other—conceptually, it is as if all the source files were concatenated into one large file before being processed. Forward declarations are never needed in C# because, with very few exceptions, declaration order is insignificant. C# does not limit a source file to declaring only one public type nor does it require the name of the source file to match a type declared in the source file.