2009-04-16 84 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(稱呼它),而不是酒吧()做()