13

I thought the method that is getting called is decided runtime, or have I missed something? Sample code:

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{}

I thought I would get:

ImplA
ImplB

as output but it prints Base impl. Is there anything I can do to get the overloaded method without casting the input?

Tomas Jansson
  • 22,767
  • 13
  • 83
  • 137

2 Answers2

18

Overloads are chosen by the compiler. For the call here:

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

it chooses the one with SomeBase, because that's all it has at compile time.

What you most probably want is overrides. This means that the different logic has to be put into the inheritors of 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);
}
Stefan Steinegger
  • 63,782
  • 15
  • 129
  • 193
  • 2
    Another possibility is that he wants to do [`double dispatch`](http://en.wikipedia.org/wiki/Double_dispatch) or use the [`visitor pattern`](http://en.wikipedia.org/wiki/Visitor_pattern). – Matthew Watson Apr 12 '13 at 08:09
  • 6
    Or the use of `dynamic`: `HiThere((dynamic)input);` This moves the overload resolution to the runtime where the exact type of `input` is known. – Daniel Hilgarth Apr 12 '13 at 08:11
  • @DanielHilgarth: That's probably the best possible implementation of double-dispatch there is. :) – Matthew Watson Apr 12 '13 at 08:16
  • @MatthewWatson: Indeed, that would be a concrete implementation of double dispatch. – Daniel Hilgarth Apr 12 '13 at 08:17
4

Overloads are selected during compilation.
Overrides are selected during runtime.

Here, compilers only knows that T can be assigned to SomeBase, but nothing else. Actually, if it worked as you expected, you would be able to completely skip the where T : SomeBase part. The reason you need it is that compiler needs to know that information in order to check what can be called on the provided object.

Zdeslav Vojkovic
  • 14,391
  • 32
  • 45