2013-04-12 27 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で1を選択します。

あなたが最も望むのは、上書きされます。

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

もう一つの可能​​性は、彼が['double dispatch'](http://en.wikipedia。 org/wiki/Double_dispatch)、または['visitor pattern'](http://en.wikipedia.org/wiki/Visitor_pattern)を使用してください。 –

+6

または 'dynamic':' HiThere((動的)入力); 'これは、' input'の正確な型がわかっているランタイムにオーバーロードの解像度を移動します。 –

+0

@DanielHilgarth:おそらく二重派遣の可能な最良の実装です。 :) –

4

オーバーロードは、コンパイル時に選択されています。これは、異なるロジックはSomeBaseの後継に入れなければならないことを意味します。
オーバーライドは実行時に選択されます。

ここで、コンパイラはTがSomeBaseに割り当てられることが分かりますが、それ以外は何も分かりません。実際には、期待どおりに動作した場合は、where T : SomeBase部分を完全にスキップすることができます。あなたが必要とするのは、提供されたオブジェクトに対して何が呼び出せるかを調べるためにコンパイラがその情報を知る必要があるからです。

関連する問題