[ Pobierz całość w formacie PDF ]
the local variable.
50 Copyright Microsoft Corporation 1999-2000. All Rights Reserved.
Chapter 3 Basic concepts
" The scope of a local variable declared in a for-initializer of a for statement is the for-initializer, the for-
condition, the for-iterator, and the contained statement of the for statement.
" The scope of a label declared in a labeled-statement is the block in which the declaration occurs.
Within the scope of a namespace, class, struct, or enumeration member it is possible to refer to the member in a
textual position that precedes the declaration of the member. For example
class A
{
void F() {
i = 1;
}
int i = 0;
}
Here, it is valid for F to refer to i before it is declared.
Within the scope of a local variable, it is an error to refer to the local variable in a textual position that precedes
the variable-declarator of the local variable. For example
class A
{
int i = 0;
void F() {
i = 1; // Error, use precedes declaration
int i;
i = 2;
}
void G() {
int j = (j = 1); // Legal
}
void H() {
int a = 1, b = ++a; // Legal
}
}
In the F method above, the first assignment to i specifically does not refer to the field declared in the outer
scope. Rather, it refers to the local variable and it is in error because it textually precedes the declaration of the
variable. In the G method, the use of j in the initializer for the declaration of j is legal because the use does not
precede the variable-declarator. In the H method, a subsequent variable-declarator legally refers to a local
variable declared in an earlier variable-declarator within the same local-variable-declaration.
The scoping rules for local variables are designed to guarantee that the meaning of a name used in an expression
context is always the same within a block. If the scope of a local variable was to extend only from its declaration
to the end of the block, then in the example above, the first assignment would assign to the instance variable and
the second assignment would assign to the local variable, possibly leading to errors if the statements of the block
were later to be rearranged.
The meaning of a name within a block may differ based on the context in which the name is used. In the
example
class Test
{
static void Main() {
string A = "hello, world";
string s = A; // expression context
Type t = typeof(A); // type context
Copyright Microsoft Corporation 1999-2000. All Rights Reserved. 51
C# LANGUAGE REFERENCE
Console.WriteLine(s); // writes "hello, world"
Console.WriteLine(t.ToString()); // writes "Type: A"
}
}
the name A is used in an expression context to refer to the local variable A and in a type context to refer to the
class A.
3.5.1 Name hiding
The scope of an entity typically encompasses more program text than the declaration space of the entity. In
particular, the scope of an entity may include declarations that introduce new declaration spaces containing
entities of the same name. Such declarations cause the original entity to become hidden. Conversely, an entity is
said to be visible when it is not hidden.
Name hiding occurs when scopes overlap through nesting and when scopes overlap through inheritance. The
characteristics of the two types of hiding are described in the following sections.
3.5.1.1 Hiding through nesting
Name hiding through nesting can occur as a result of nesting namespaces or types within namespaces, as a result
of nesting types within classes or structs, and as a result of parameter and local variable declarations. Name
hiding through nesting of scopes always occurs silently , i.e. no errors or warnings are reported when outer
names are hidden by inner names.
In the example
class A
{
int i = 0;
void F() {
int i = 1;
}
void G() {
i = 1;
}
}
within the F method, the instance variable i is hidden by the local variable i, but within the G method, i still
refers to the instance variable.
When a name in an inner scope hides a name in an outer scope, it hides all overloaded occurrences of that name.
In the example
class Outer
{
static void F(int i) {}
static void F(string s) {}
class Inner
{
void G() {
F(1); // Invokes Outer.Inner.F
F("Hello"); // Error
}
static void F(long l) {}
}
}
52 Copyright Microsoft Corporation 1999-2000. All Rights Reserved.
Chapter 3 Basic concepts
the call F(1) invokes the F declared in Inner because all outer occurrences of F are hidden by the inner
declaration. For the same reason, the call F("Hello") is in error.
3.5.1.2 Hiding through inheritance
Name hiding through inheritance occurs when classes or structs redeclare names that were inherited from base
classes. This type of name hiding takes one of the following forms:
" A constant, field, property, event, or type introduced in a class or struct hides all base class members with
the same name.
" A method introduced in a class or struct hides all non-method base class members with the same name, and
all base class methods with the same signature (method name and parameter count, modifiers, and types).
" An indexer introduced in a class or struct hides all base class indexers with the same signature (parameter
count and types).
The rules governing operator declarations (§10.9) make it impossible for a derived class to declare an operator
with the same signature as an operator in a base class. Thus, operators never hide one another.
Contrary to hiding a name from an outer scope, hiding an accessible name from an inherited scope causes a
warning to be reported. In the example
class Base
{
public void F() {}
}
class Derived: Base
{
public void F() {} // Warning, hiding an inherited name
}
the declaration of F in Derived causes a warning to be reported. Hiding an inherited name is specifically not an
error, since that would preclude separate evolution of base classes. For example, the above situation might have
come about because a later version of Base introduced a F method that wasn t present in an earlier version of
the class. Had the above situation been an error, then any change made to a base class in a separately versioned
class library could potentially cause derived classes to become invalid.
The warning caused by hiding an inherited name can be eliminated through use of the new modifier:
class Base
{
public void F() {}
}
class Derived: Base
{
new public void F() {}
}
The new modifier indicates that the F in Derived is new , and that it is indeed intended to hide the inherited
member.
A declaration of a new member hides an inherited member only within the scope of the new member.
class Base
{
public static void F() {}
}
[ Pobierz całość w formacie PDF ]