Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
    }
}
like image 358
Loic Jourdan Avatar asked Aug 01 '26 14:08

Loic Jourdan


2 Answers

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.

like image 141
Jon Skeet Avatar answered Aug 04 '26 02:08

Jon Skeet


If you change the extension method to this:

public static string GetCaption<T>(T t) where T : MyClass

Then it will call the MyClass extension method as the compiler can tell that this is the most specific method to call.

Without the where T : MyClass then the object extension method is the most specific that it can determine at compile-time.

When I run your code with where T : MyClass I get:

object caption 0
MyClass caption
MyClass caption

Without it, exactly as you posted it, I get:

object caption 0
MyClass caption
object caption MyClass

Here is the full working program.

//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) where T : MyClass
    {
        //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
    }
}
like image 42
Enigmativity Avatar answered Aug 04 '26 03:08

Enigmativity



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!