2009-04-16 87 views
6

下面的代码应该给出警告吗?为什么我的Static方法隐藏我的实例方法?

class Foo { public void Do() { /*...*/ } /*...*/ } 
class Bar : Foo { public static void Do() { /*...*/ } /*...*/ } 

它提供:

“警告CS0108: 'Bar.Do()' 隐藏了继承的成员 'Foo.Do()' 使用new关键字隐藏,如果是打算。”

如果我进行了更改代码:

class Foo { public static void Do() { /*...*/ } /*...*/ } 
class Bar : Foo { public void Do() { /*...*/ } /*...*/ } 

我得到同样的警告。

但是,如果我做了以下更改,警告消失。

class Foo { public void Do() { /*...*/ } /*...*/ } 
class Bar : Foo { new public static void Do() { /*...*/ } /*...*/ } 

让我做出进一步的变化:

class Foo { public void Do() { /*...*/ } /*...*/ } 
class Bar : Foo { 
    new public static void Do() 
    { new Bar().Do();/*...*/ } /*...*/ 
} 

这并不编译:

“错误CS0176:会员 'Bar.Do()' 不能用一个实例来访问引用;改为使用类型名称对其进行限定。“

于是,我通过从一个静态方法实例引用失去了我的继承方法的访问!

它背后的逻辑是什么?或者我在某处犯了一个错字?

我碰到这个来的时候,我试图定义一个静态方法“显示”从“形式”得出自己的状态。

回答

5

您认为该错误在哪里?有警告的事实是绝对正确的。从C#3.0规范,部分10.3.4:

一类成员声明是 允许声明与 相同名称或签名作为继承 构件的部件。当发生这种情况时,派生的 类成员据说会隐藏基类 类成员。隐藏继承 成员不算是一个错误,但 确实会导致编译器发出警告 。为了抑制警告,该 声明派生类 成员可以包括new修饰符来 表示派生成员是 打算隐藏基成员。

,你的方法调用失败的事实是微妙的,但它主要是因为成员查找算法采静态方法,然后使用7.5.5.1节的这部分:

的最终确认执行所选择的最好的方法 :

该方法是 验证在该方法 组的上下文:如果该最佳方法是静态 方法,该方法组必须具有 通过简单名称或 成员访问通过类型产生。如果 最好方法是一个实例的方法,所述方法 组必须从 简单名称,通过 变量或值,或者一个基本访问成员访问。 如果这两项要求都不是 ,则会发生编译时错误。

2

不,这非常有意义。这按预期工作:

using System; 
using System.Collections.Generic; 

class Foo { public void Do() { /*...*/ } /*...*/ } 
class Bar : Foo { 
    new public static void Do() 
    { ((Foo)new Bar()).Do();/*...*/ } /*...*/ 
} 

这是因为编译器假定你有一个酒吧类型,然后找到静态成员。通过将它转换为Foo(可以免费使用btw),您可以在Foo()的metdadata中查找,并且一切正常。

+0

当我说。 “新的酒吧()做();”。我肯定会调用实例方法“Do”,它可以在Bar via Foo中找到。那么,为什么我们必须输入演员? – isntn 2009-04-16 16:28:03

+1

因为编译器不查看实例,而是查看类型元数据。在这里它只找到一个具有正确签名(名称和空参数列表)的方法,这是静态的。 – Lucero 2009-04-16 16:29:11

+0

用虚拟功能表来考虑它; Bar :: Do()映射隐藏了Foo:Do()的映射。 – 2009-04-16 16:32:42

2

试试这个:

 new public static void Do() 
     { 
      ((Foo)new Bar()).Do(); 
     } 
0

在您的最终代码示例中,新的关键字上Bar.Do的()的声明意味着你要隐藏Foo.Do()。

0

出于好奇,为什么你要这么做?看起来你可能正在错误地解决你的解决方案。

上面的代码出现,因为它应该工作,和编译器的消息告诉你有什么问题。

1

,你应该能够做主叫base.Do(称呼它),而不是酒吧()做()