2010-09-05 74 views
9
class Base 
{ 
    public virtual void MethodA(int x) 
    { 
     Console.WriteLine ("In Base Class"); 
    } 
} 

class Derived : Base 
{ 
    public override void MethodA(int x) 
    { 
     Console.WriteLine ("In derived INT)"); 
    } 

    public void MethodA(object o) 
    { 
     Console.WriteLine ("In derived OBJECT"); 
    } 
} 

class Test 
{ 
    static void Main() 
    { 
     Derived d = new Derived(); 
     int k = 20; 
     d.MethodA(k); 
    } 
} 

我得到的這個輸出是「在導出的OBJECT」。這種奇怪的行爲是什麼原因?經過一番研究,我發現原因是在基類中聲明的簽名被忽略。他們爲什麼被忽略?爲什麼在基類中聲明的簽名被忽略?

+1

+1的問題,我同意這是違反直覺的行爲。 – 2010-09-05 22:30:03

+0

我同意這種行爲很奇怪。我想知道:你問這是因爲你真的想要這麼做還是因爲你好奇?我看不出有什麼理由實際執行這樣的事情,但我一定想知道它爲什麼會發生。 – 2010-09-05 22:41:08

+0

[C#中的方法隱藏如何工作? (Part Two)](http://stackoverflow.com/questions/710459/how-method-hiding-works-in-c-part-two) – 2010-09-05 22:57:33

回答

6

這是設計和一個很好的理由。這種設計有助於防止脆性基座類問題。 C#旨在讓編寫「版本化」組件變得更加簡單和安全,而這一規則是其中的重要組成部分。

這是一個非常常見的問題。這是我們得到的最常見的「虛假錯誤報告」之一;也就是說,有人認爲他們在編譯器中發現了一個錯誤,實際上他們發現了一個功能。

對於功能的說明,爲什麼它是專事情是這樣的,看到我的主題文章:

http://blogs.msdn.com/b/ericlippert/archive/2007/09/04/future-breaking-changes-part-three.aspx

有關如何各種語言與脆處理該問題的更多文章基類問題看關於這個問題我的文章歸檔:

http://blogs.msdn.com/b/ericlippert/archive/tags/brittle+base+classes/

2

當決定要調用什麼時,VC#2008中的編譯器在虛擬函數之前檢查可用的非虛函數。由於您的Derived類具有可以調用的非虛擬MethodA(對象),編譯器會調用它。

如果向Base添加虛擬MethodA(對象),則將調用Derived.MethodA(int),因爲那麼MethodA(object)和MethodA(int)都是虛擬的。

我對C#語言規範不夠熟悉,不知道這是指定行爲還是編譯器中的錯誤。

+0

確實在ECMA規範中,非虛擬將首先被調用。另請注意,調用的方法由編譯器針對非虛擬方法以及虛擬方法的運行時類型確定。 – 2010-09-05 22:56:46

+0

我檢查了這一點,但要小心Derived.MethodA(int)只會在將關鍵字'override'添加到Derived.MethodA(object)(當然是這個意思)時被調用。沒有它,假定可選關鍵字'new',並且Derived.MethodA(object)仍然會被調用。 – Gerard 2010-10-19 10:40:13