首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >泛型方法是如何、何时、何地具体化的?

泛型方法是如何、何时、何地具体化的?
EN

Stack Overflow用户
提问于 2013-10-17 02:07:33
回答 2查看 1.9K关注 0票数 72

This question让我想知道泛型方法的具体实现是从哪里开始的。我已经尝试了谷歌,但没有找到正确的搜索结果。

如果我们举这个简单的例子:

代码语言:javascript
复制
class Program
{
    public static T GetDefault<T>()
    {
        return default(T);
    }

    static void Main(string[] args)
    {
        int i = GetDefault<int>();
        double d = GetDefault<double>();
        string s = GetDefault<string>();
    }
}

在我的脑海中,我一直认为,在某些时候,它会导致一个具有3个必要的具体实现的实现,这样,在朴素的伪mangling中,我们会有这个逻辑上的具体实现,其中使用的特定类型会导致正确的堆栈分配等。

代码语言:javascript
复制
class Program
{
    static void Main(string[] args)
    {
        int i = GetDefaultSystemInt32();
        double d = GetDefaultSystemFloat64();
        string s = GetDefaultSystemString();
    }

    static int GetDefaultSystemInt32()
    {
        int i = 0;
        return i;
    }
    static double GetDefaultSystemFloat64()
    {
        double d = 0.0;
        return d;
    }
    static string GetDefaultSystemString()
    {
        string s = null;
        return s;
    }
}

看看泛型程序的IL,它仍然是用泛型类型表示的:

代码语言:javascript
复制
.method public hidebysig static !!T  GetDefault<T>() cil managed
{
  // Code size       15 (0xf)
  .maxstack  1
  .locals init ([0] !!T CS$1$0000,
           [1] !!T CS$0$0001)
  IL_0000:  nop
  IL_0001:  ldloca.s   CS$0$0001
  IL_0003:  initobj    !!T
  IL_0009:  ldloc.1
  IL_000a:  stloc.0
  IL_000b:  br.s       IL_000d
  IL_000d:  ldloc.0
  IL_000e:  ret
} // end of method Program::GetDefault

那么如何以及在什么时候决定在堆栈上分配int、double和string并返回给调用者呢?这是JIT流程的一个操作吗?我对这件事的看法完全错了吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-10-17 02:14:42

在C#中,运行库本身支持泛型类型和方法的概念。C#编译器不需要实际创建泛型方法的具体版本。

实际的“具体”泛型方法是由JIT在运行时创建的,并不存在于IL中。第一次将泛型方法用于某个类型时,JIT将查看它是否已创建,如果没有,则为该泛型类型构造适当的方法。

这是泛型与C++中的模板之类的东西之间的基本区别之一。这也是泛型存在许多限制的主要原因--因为编译器实际上并没有为类型创建运行时实现,所以接口限制是由编译时约束处理的,这使得泛型在潜在用例方面比C++中的模板更具限制性。但是,运行时本身支持泛型类型这一事实允许从库中创建泛型类型和使用,而在C++和其他编译时创建的模板实现中不支持这种方式。

票数 78
EN

Stack Overflow用户

发布于 2013-10-17 02:16:07

泛型方法的实际机器码通常是在方法被The时创建的。在这一点上,抖动首先检查以前是否有合适的候选者被抖动过。通常情况下,具体运行时类型T是引用类型的方法的代码只需要生成一次,并且适用于每个可能的引用类型T。T上的约束确保这个机器代码总是有效的,以前由C#编译器检查过。

可以为值类型的T生成额外的副本,它们的机器代码是不同的,因为T值不再是简单的指针。

所以,是的,在您的例子中,您最终将得到三个不同的方法。<string>版本可用于任何引用类型,但您没有其他版本。<int><double>版本符合"T's are value type“类别。

另外一个很好的例子是,这些方法的返回值以不同的方式传回调用者。在x64抖动时,字符串版本通过RAX寄存器返回值,就像任何返回的指针值一样,int版本通过EAX寄存器返回,双精度版本通过XMM0寄存器返回。

票数 45
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19410634

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档