10.3 Declarations
Declarations in a C# program define the constituent elements of the program.
C# programs are organized
using namespaces (?6), which can contain type declarations and nested
namespace declarations. Type
declarations (?6.5) are used to define classes (?7), structs (?8),
interfaces (?0), enums (?1), and
delegates (?2). The kinds of members permitted in a type declaration
depend on the form of the type
declaration. For instance, class declarations can contain declarations for
constants (?7.3), fields (?7.4),
methods (?7.5), properties (?7.6), events (?7.7), indexers (?7.8),
operators (?7.9), instance
constructors (?7.10), destructors (?7.12), static constructors (?7.11),
and nested types.
A declaration defines a name in the declaration space to which the
declaration belongs. Except for
overloaded members (?0.6), it is a compile-time error to have two or more
declarations that introduce
members with the same name in a declaration space. However, no diagnostic
is required if the declaration
space is a namespace for the global declaration space and the conflicting
declarations are in separate
programs. It is never possible for a declaration space to contain different
kinds of members with the same
name. [Example: For example, a declaration space can never contain a field
and a method by the same name.
end example]
There are several different types of declaration spaces, as described in
the following.
?Within all source files of a program, namespace-member-declarations with
no enclosing namespacedeclaration
are members of a single combined declaration space called the global
declaration space.
?Within all source files of a program, namespace-member-declarations
within namespace-declarations
that have the same fully qualified namespace name are members of a single
combined declaration space.
?Each class, struct, or interface declaration creates a new declaration
space. Names are introduced into
this declaration space through class-member-declarations,
struct-member-declarations, or interfacemember-
declarations. Except for overloaded instance constructor declarations and
static constructor
declarations, a class or struct member declaration cannot introduce a
member by the same name as the
class or struct. A class, struct, or interface permits the declaration of
overloaded methods and indexers.
Furthermore, a class or struct permits the declaration of overloaded
instance constructors and operators.
[Example: For example, a class, struct, or interface may contain multiple
method declarations with the
same name, provided these method declarations differ in their signature (?0.
6). end example] Base
classes do not contribute to the declaration space of a class, and base
interfaces do not contribute to the
declaration space of an interface. Thus, a derived class or interface is
allowed to declare a member with
the same name as an inherited member. Such a member is said to hide the
inherited member.
?Each enumeration declaration creates a new declaration space. Names are
introduced into this
declaration space through enum-member-declarations.
?Each block or switch-block creates a declaration space for local
variables and local constants. Names are
introduced into this declaration space through local-variable-declarations
and local-constantdeclarations.
If a block is the body of an instance constructor, method, or operator
declaration, or a get
or set accessor for an indexer declaration, the parameters declared in such
a declaration are members of
the block.s local variable declaration space. The local variable
declaration space of a block includes
any nested blocks. Thus, within a nested block it is not possible to
declare a local variable or constant
with the same name as a local variable or constant in an enclosing block.
Chapter 10 Basic concepts
71
?Each block or switch-block creates a separate declaration space for
labels. Names are introduced into
this declaration space through labeled-statements, and the names are
referenced through gotostatements.
The label declaration space of a block includes any nested blocks. Thus,
within a nested
block it is not possible to declare a label with the same name as a label
in an enclosing block.
The textual order in which names are declared is generally of no
significance. In particular, textual order is
not significant for the declaration and use of namespaces, constants,
methods, properties, events, indexers,
operators, instance constructors, destructors, static constructors, and
types. Declaration order is significant in
the following ways:
?Declaration order for field declarations and local variable declarations
determines the order in which
their initializers (if any) are executed.
?Local variables must be defined before they are used (?0.7).
?Declaration order for enum member declarations (?1.3) is significant
when constant-expression values
are omitted.
[Example: The declaration space of a namespace is .open ended., and two
namespace declarations with the
same fully qualified name contribute to the same declaration space. For
example
namespace Megacorp.Data
{
class Customer
{
.
}
}
namespace Megacorp.Data
{
class Order
{
.
}
}
The two namespace declarations above contribute to the same declaration
space, in this case declaring two
classes with the fully qualified names Megacorp.Data.Customer and
Megacorp.Data.Order. Because
the two declarations contribute to the same declaration space, it would
have caused a compile-time error if
each contained a declaration of a class with the same name. end example]
[Note: As specified above, the declaration space of a block includes any
nested blocks. Thus, in the
following example, the F and G methods result in a compile-time error
because the name i is declared in the
outer block and cannot be redeclared in the inner block. However, the H and
I methods are valid since the
two i.s are declared in separate non-nested blocks.
class A
{
void F() {
int i = 0;
if (true) {
int i = 1;
}
}
void G() {
if (true) {
int i = 0;
}
int i = 1;
}
C# LANGUAGE SPECIFICATION
72
void H() {
if (true) {
int i = 0;
}
if (true) {
int i = 1;
}
}
void I() {
for (int i = 0; i < 10; i++)
H();
for (int i = 0; i < 10; i++)
H();
}
}
end note]