通用函数与扩展方法

Loi*_*dan 3 c# generics extension-methods

我是一名尝试使用 C# 泛型的 C++ 开发人员。我的最终目标是模仿 C# 中的模板专业化。

换句话说,我想要一个可用于所有类型的函数的默认实现和一个特定类型的特定实现。

我的第一次尝试是使用泛型和扩展方法,但似乎 C# 泛型是在运行时解析的,这给出了这个奇怪的结果(至少对于 C++ 程序员来说很奇怪):

//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
    }
}
Run Code Online (Sandbox Code Playgroud)

在 C# 中处理这种情况的通常方法是什么?

编辑:

尝试实施@Enigmativity建议,我尝试过但没有成功:

//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
    }
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 7

我的最终目标是模仿 C# 中的模板专业化。

老实说,我认为这不太可能有好结果。泛型不像C++ 模板;它们用于实现相似的目标,但采用的方法却截然不同。

我的第一次尝试是使用泛型和扩展方法,但似乎 C# 泛型是在运行时解析的

不,这不是真的——这解释了你得到的结果。

编译 的代码时,编译器会在不了解 的情况下GetCaption<T>解析对 的调用,因此它可以调用的唯一扩展方法是具有第一个参数类型的扩展方法- 这就是您所看到的。t.GetCaption()Tobject

基本上,您需要记住每个泛型方法仅编译一次- 而不是针对每个类型参数编译一次。一切都源于这种理解:您可以像平常一样在重写方面看到多态性,但在编译时选择不同方法时不会重载。

  • 是的:`GetCaption&lt;T&gt;` 的 IL 仍然“知道”它是通用的,并且有一个用于它的 IL。编译 GetCaption&lt;T&gt; 时,编译器不知道任何关于 T 的信息,因为 GetCaption&lt;T&gt; 的使用可能是在尚未编写的代码中。 (2认同)