Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C#: Generic method doesn't call specific method overload

I am trying to create a generic method in C#, which will call different methods based on the argument datatype in its body and process their result afterwards. I am trying to achieve this by creating a generic wrapper method and then provide several overloads of the processing method - including a generic one that'll be used if no specific overload is available.

When I call the processing method directly, appropriate version is correctly selected. However when I call it from the wrapper method it always selects the generic one, even if there's a matching overload for the specific datatype I passed to it.

Is there any way to adjust the code to make it behave the way I need to? Or do I have to use a different approach.

I need the code to be compatible with Mono 2.6.

using System;

class Program
{
    static void Func<T>(T val)
    {
        Console.WriteLine("Generic Func");
    }

    static void Func(int val)
    {
        Console.WriteLine("Int Func");
    }

    static void Func(string val)
    {
        Console.WriteLine("String Func");
    }

    static void FuncWrap<T>(T val)
    {
        Console.Write("Wrap: ");
        Func(val);
    }

    static void Main(string[] args)
    {
        Func(2);
        Func("Potato");
        Func(2.0);

        FuncWrap(2);
        FuncWrap("Potato");
        FuncWrap(2.0);

        Console.Read();
    }
}
like image 838
Tom Frooxius Mariank Avatar asked Sep 05 '14 12:09

Tom Frooxius Mariank


1 Answers

Is there any way correct this behavior?

It's already the correct behaviour according to the C# language specification. The overload of Func called within FuncWrap is normally determined at compile time, so it can't pick a different Func overload based on the execution-time type.

One way of changing the behaviour, however, is to use dynamic typing:

static void FuncWrap<T>(T val)
{
    Console.Write("Wrap: ");
    dynamic x = val;
    Func(x);
}

That will now perform overload resolution at execution time based on the actual type of the value of x. This incurs a performance cost, but should do what you want it to.

Alternatively, you could hard-code knowledge of the overloads:

static void FuncWrap<T>(T val)
{
    Console.Write("Wrap: ");
    if (typeof(T) == typeof(string))
    {
        Func((string)(object)val);
    }
    else if (typeof(T) == typeof(int))
    {
        Func((int)(object)val);
    }
    else
    {
        Func(val);
    }
}

That's clearly pretty horrible though.

like image 70
Jon Skeet Avatar answered Oct 13 '22 18:10

Jon Skeet