开发工具与关键技术:Microsoft Visual Studio 2015、.NET
撰写时间:2019年08月06日
典型情况下,一个实体的范围比实体本身的声明域要涉及更多的程序文字。特别是,一个实体的范围可能会包括声明,这些声明会引入一些包含有相同名称的实体的新声明域。这样的声明会使原来的实体变为隐藏。相反,当一个实体不是隐藏的时候,称为可视。
当嵌套引起范围重叠时和当继承引起范围重叠时,就会出现名称隐藏。两种隐藏的特征在下面描述。
(一)通过嵌套隐藏
出现在当名称空间中的名称空间和类型的嵌套,或者类和结构中的类型嵌套,或者是参数和局部变量声 明的都会造成通过嵌套隐藏名称的出现。通过嵌套隐藏名称通常是“安静地”发生,也就是当外部名称 被内部名称隐藏起来时,不会报告错误和警告。
在这个例子中
class A
{
int i = 0;
void F()
{
int i = 1;
}
void G()
{
i = 1;
}
}
在方法 F中,实例变量 I被局部变量 I隐藏了,但是在方法 G中,I还是引用实例变量。
当一个内部范围的名称隐藏一个外部范围的名称,它会把那个名称的所有重载都隐藏。
在例子中
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) { }
}
}
对F(1)的调用实际调用了在内层声明的F,因为所有F的外部事件都被内部声明隐藏了。出于相同的原因,调用F(“Hello”)是错误的。
(二)通过继承隐藏
名称通过继承隐藏在类或结构重新对从基类继承来的名称声明时发生。这种类型的名称隐藏有下面形式中的一种:
• 一个引入类或结构的常数、域、属性、事件或类型隐藏了所有基类中名称相同的成员。
• 一个引入类或结构的方法隐藏了所有有相同名称的非方法基类成员和所有有相同签名的基类成员(方法名称和参数数目、修饰符和类型)。
• 一个引入类或结构的索引隐藏所有有相同签名的基类索引(参数数目和类型)。
管理操作符声明(§10.9)的规则使得一个派生类可以用与基类中的一个操作符相同的签名声明一个操作 符。这样,操作符就不会隐藏其它的操作符。
与隐藏外部范围的名称相反,隐藏继承范围的可访问名称就会报告警告。
在例子中
class Base
{
public void F() { }
}
class Derived : Base
{
public void F() { } // Warning, hiding an inherited name
}
在Derived中F的声明产生了一个警告报告。隐藏一个继承的名称肯定不是错误,因为这样将排除基类单独更新。例如,因为 Base后来的版本把不在先前版本类中的 F方法引入,这样就会产生上面的情况。如果上面的情况是一个错误,那么任何对于在独立版本类库中的基类的变更就会潜在地使得派生类变为无效。
由于继承名称引起的警告可以通过使用新修饰符来消除:
class Base
{
public void F() { }
}
class Derived : Base
{
new public void F() { }
}
新的修饰符指出Derived中的F是“新”,并且它实际上是要隐藏继承成员。
新成员的声明只是在新成员的范围内隐藏继承的成员。
class Base
{
public static void F() { }
}
class Derived : Base
{
new private static void F() { } // Hides Base.F in Derived only
}
class MoreDerived : Derived
{
static void G(){F();} // Invokes Base.F
}
在上面的例子中,Derived中F的声明隐藏了从 Base继承的F,但是由于Derived中的新F有私有的可访问性,所以它的范围不会扩展到MoreDerived。这样,MoreDerived.G中对 F()的调用是有效的,并且会引用 Base.F。