Search code examples
c#genericsextension-methods

Generic functions vs extension methods


I'm a C++ developer who tries to play with C# generics. My final goal is to mimic template specialization in C#.

In other term, I want a default implementation of a function available for all types and a specific implementation for a specific type.

My first attempt was with generics and extension methods but it seems C# generics are resolved at run-time, which gives this weird result (weird for a C++ programmer at least):

//any of my classes
public class MyClass
{
}

//class extension for my classes only
public static class MyClassExt
{
    public static string GetCaption(this MyClass c)
    {
        return "MyClass caption";
    }
}

//"default" extension for all
public static class objectExt
{
    public static string GetCaption(this object o)
    {
        return $"object caption {o}";
    }
}

internal class Program
{
    public static string GetCaption<T>(T t)
    {
        //Isn't it supposed to call MyClassExt.GetCaption if t is MyClass ?
        return t.GetCaption();
    }

    static void Main(string[] args)
    {
        int i = 0;
        Console.WriteLine(i.GetCaption());              //> object caption 0
        Console.WriteLine(new MyClass().GetCaption());  //> MyClass caption

        //calls GetCaption<T> with T is MyClass
        Console.WriteLine(GetCaption(new MyClass()));   //> object caption csharpconsole.MyClass
    }
}

What is the usual way to handle such case in C#?

Edit:

trying to implement @Enigmativity suggestion, I've tried this with no success:

//class extension for my classes only
public static class MyClassExt
{
    //My attempt for @Enigmativity suggestion
    public static string GetCaption<T>(this T t) where T : MyClass
    {
        return "MyClass caption";
    }
}

//"default" extension for all
public static class objectExt
{
    public static string GetCaption(this object o)
    {
        return $"object caption {o}";
    }
}

internal class Program
{
    public static string GetCaption<T>(T t)
    {
        //Isn't it supposed to call MyClassExt.GetCaption if t is MyClass ?
        return t.GetCaption();
    }

    static void Main(string[] args)
    {
        int i = 0;
        Console.WriteLine(i.GetCaption());              //> object caption 0
        Console.WriteLine(new MyClass().GetCaption());  //> MyClass caption
        
        //calls GetCaption<T> with T is MyClass
        Console.WriteLine(GetCaption(new MyClass()));   //> object caption csharpconsole.MyClass
    }
}

Solution

  • My final goal is to mimic template specialization in c#.

    I think that's unlikely to end well, to be honest. Generics aren't like C++ templates; they're used to accomplish similar goals, but with quite different approaches.

    My first attempt was with generics and extension methods but it seems c# generics are resolved at run-time

    No, that's not true - which explains the result you're getting.

    When compiling the code for GetCaption<T>, the compiler resolves the call to t.GetCaption() without knowing anything about T, so the only extension method it can call is the one with the first parameter of type object - which is what you're seeing.

    Basically, you need to remember that each generic method is only compiled once - not once against each type argument. Everything flows from that understanding: you can see polymorphism in terms of overriding, as normal, but not overloading where a different method is chosen at compile-time.