2013-04-12 128 views
13

我認爲被調用的方法是運行時決定的,還是我錯過了某些東西?示例代碼:爲什麼重載的方法不被調用?

class Program 
{ 
    static void Main(string[] args) 
    { 
     var magic = new MagicClass(); 
     magic.DoStuff(new ImplA()); 
     magic.DoStuff(new ImplB()); 
     Console.ReadLine(); 
    } 
} 
class MagicClass 
{ 
    internal void DoStuff<T>(T input) where T : SomeBase 
    { 
     HiThere(input); 
    } 

    void HiThere(SomeBase input) 
    { 
     Console.WriteLine("Base impl"); 
    } 

    void HiThere(ImplA input) 
    { 
     Console.WriteLine("ImplA"); 
    } 

    void HiThere(ImplB input) 
    { 
     Console.WriteLine("ImplB"); 
    } 
} 

abstract class SomeBase 
{ 

} 
class ImplA : SomeBase{} 
class ImplB : SomeBase{} 

我想我會得到:

ImplA 
ImplB 

作爲輸出,但它打印Base impl。有沒有什麼我可以做,而不是投入輸入重載的方法?

+2

這是一個相當不錯的解釋爲什麼:http://csharpindepth.com/Articles/General/Overloading.aspx –

回答

18

重載由編譯器選擇。對於呼叫這裏:

internal void DoStuff<T>(T input) where T : SomeBase 
{ 
    HiThere(input); 
} 

它選擇了一個與SomeBase,因爲這一切都在編譯時間。

你最可能想要的是覆寫。這意味着不同的邏輯必須放入SomeBase的繼承者中:

abstract class SomeBase 
{ 
    abstract string Name { get; } 
} 
class ImplA : SomeBase{ override string Name { get { return "ImplA"; } } } 
class ImplB : SomeBase{ override string Name { get { return "ImplB"; } } } 

void HiThere(SomeBase input) 
{ 
    Console.WriteLine(input.Name); 
} 
+2

另一種可能是他想做['雙派遣'](http://en.wikipedia。 org/wiki/Double_dispatch)或使用['visitor pattern'](http://en.wikipedia.org/wiki/Visitor_pattern)。 –

+6

或使用'dynamic':'HiThere((動態)輸入);'這將重載分辨率移動到確切類型的輸入已知的運行時間。 –

+0

@DanielHilgarth:這可能是雙派遣的最佳實現。 :) –

4

在編譯過程中選擇了重載。
在運行期間選擇覆蓋。

在這裏,編譯器只知道T可以被分配到SomeBase,但沒有別的。實際上,如果它按照預期工作,那麼您完全可以跳過where T : SomeBase部分。你需要它的原因是編譯器需要知道這些信息,以便檢查提供的對象上可以調用的內容。

相關問題