2011-11-15 43 views
7

我只是偶然發現了一個非常有趣的問題。給下面的代碼:多態方法不適用於C#4

using System; 

class Program 
{ 
    class A { } 
    class B : A { } 

    private static void MyMethod(A a) /* first method */ 
    { 
     Console.WriteLine("A"); ; 
    } 

    private static void MyMethod(B b) /* second method */ 
    { 
     Console.WriteLine("B"); 
    } 

    static void Main(string[] args) 
    { 
     var a = new A(); 
     // Call first method 
     MyMethod(a); 

     A b = new B(); 
     // Should call the second method 
     MyMethod(b); 

     Console.ReadLine(); 
    } 
} 

我會想到的是,第二個方法將被調用,因爲變量的運行時類型爲B.任何想法,爲什麼代碼調用第一種方法呢?

感謝, 提筆

一些澄清:多態性是指無關,你聲明的方法幾種形式。

方法重載是多態的一種形式,ad-hoc多態。

通常使用遲綁定來實現多態的方式。

動態是解決此問題的方法。

事實上,這不是在C#(或Java)中工作,它是一個設計決定,我想知道爲什麼做了,沒有答案回答這個問題。

/Tibi

+4

這不是多態,你有兩個相同方法的重載實例,每個實例都以不同的類型作爲參數。然後你聲明「b」爲A.編譯器讓你這樣做,因爲B繼承了A. – Maess

回答

6

默認情況下,C#中的方法重載是在編譯時靜態確定的。由於您傳遞的是A類型的靜態類型變量,因此它將靜態綁定到具有A重載的方法。使用動態關鍵字來獲得你想要的行爲。

static void Main(string[] args) 
{ 
    dynamic d = new A(); 
    // Call first method 
    MyMethod(d); 

    d = new B(); 
    // Call the second method 
    MyMethod(d); 

    Console.ReadLine(); 
} 
+0

我沒有想到!謝謝。 – Tibi

+0

我實際上並不知道'dynamic'關鍵字會導致對重載方法的調用在運行時解析,這是很容易知道的。儘管如此,我很好奇這種後期綁定的潛在性能問題。 –

+1

我猜你會在第一次使用新的參數類型調用它時導致一些性能命中,因爲它需要解析,但隨後由DLR緩存。 – Tibi

14

這根本不是多態性的例子。當您將方法調用到對象上時,而不是在對象用作參數時,多態性進入播放狀態。這只是方法重載的一個簡單例子。

您將b聲明爲A類型,因此編譯器將鏈接到使用類型A的重載。鏈接器不關心B是A的子類,它只是選擇最靠近對傳入參數的聲明類型(不是實際類型)進行簽名。

如果要強制它使用第二種方法,請在方法調用中將b轉換爲類型B.

MyMethod((B)b); 
+0

確實。 Java中也發生過相同的事情。預期的行爲。 – EdH

+0

在更復雜的情況下,鑄造只會使代碼變得醜陋。無論如何,我希望鏈接器關心參數的類型,並使用後期綁定。 – Tibi

+1

如果你想要它的行爲,你應該把'DoSomething'子放在'A'上,並用'B'覆蓋它。然後當你調用'b.DoSomething()'時,它會根據實際的類型選擇正確的。 –

0

它不調用第二種方法,因爲參考b本身是A類型。雖然b包含對B實例的引用,但這不是B的實際類型,因此選擇使用A引用的超載。

+0

我完全理解它做了什麼,我只是不明白爲什麼。 – Tibi

+1

方法調用在編譯時解析。 ('動態'類型'方法排除在外)這就是爲什麼。 – recursive

+0

多態方法在運行時解決。 – Tibi

相關問題