首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么泛型代码应该在不限制T的情况下编译?

为什么泛型代码应该在不限制T的情况下编译?
EN

Stack Overflow用户
提问于 2016-04-13 15:13:10
回答 3查看 109关注 0票数 7

下面的代码片段是从编程C# 5.0的示例10-11 (第343页)中提取的

代码语言:javascript
复制
public static T[] Select<T>(this CultureInfo[] cultures,
                            Func<CultureInfo, T> map)
{
    var result = new T[cultures.Length];
    for (int i = 0; i < cultures.Length; ++i)
    {
        result[i] = map(cultures[i]);
    }
    return result;
}

我想不出如何通过在T上应用约束来编译它而不公开任何关于它的信息。具体来说,编译器如何知道要为数组分配多少字节,考虑到T可能不是引用类型,而是值类型(即struct)?此外,赋值操作result[i] = map(cultures[i])的语义似乎取决于T是引用类型还是值类型。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-04-13 15:31:25

我认为,理解这一点的关键是以下几点:

首先,在编译时创建一个通用方法,它只是您在源代码中所写内容的IL版本。它是type issue (map返回一个T,数组单元格是T类型的,因此没有问题),一切都很好。

现在,在运行时,(至少在概念上)第一次使用Select<string>时,JIT编译器就会创建一个新的方法。让我们将这个方法称为Select__string (实际上它通常被称为类似于Select'string的东西,但我不希望您认为为了这个解释的目的,这很重要)。在这个新方法中,T的所有实例都被string替换,因此在编译后的方法中,一切都很容易计算--赋值、数组大小分配等等。

接下来,您可以在其他地方做Select<int>。JIT编译器现在创建一个全新的方法,我们称之为Select__int。而且,T的所有实例都被int替换,因此,数组大小和赋值语义也很容易处理。

泛型类型也是如此。当它们真正被使用时,List<string>List<int>是两个完全不同的类型。这就是为什么.net泛型如此容易编写和使用的原因。

如果这一点还不清楚,您能给出一个示例,说明在上面的代码中,您认为在编译时仍然需要知道或限制什么吗?

票数 3
EN

Stack Overflow用户

发布于 2016-04-13 15:17:30

CultureInfoT之间不存在任何依赖关系。所有的T都同样有效,因为您使用自定义Func<CultureInfo, T>来处理“转换”。

我认为您对泛型在C#中的工作方式感到困惑。它们不是编译时特性(就像Java中的那样),它们一直存在到运行时。只有当您实际需要一个具体化的泛型类型时,才会编译该类型,到那时,它已经知道了T是什么。

这当然是C#没有List<?>的原因之一。没有“公共泛型类型”,只是“延迟”了类型的具体化--一旦有了List<string>List<int>,这两种类型就完全不同了,只有反射才能告诉您它们来自同一泛型类型。

票数 9
EN

Stack Overflow用户

发布于 2016-04-13 15:24:04

具体来说,编译器如何知道要为数组分配多少字节,

不需要编译器知道这一点。

但是,假设确实需要给newarr指令一个字节大小。然后编译器可以简单地让元素类型的大小和数组的长度的乘法在运行时执行。

此外,赋值操作result[i] = map(cultures[i])的语义似乎取决于T是引用类型还是值类型。

这不取决于此。不管类型如何,无论map返回的是什么,都会生成一个精确的副本。如果它是一个值类型,这意味着该值将被复制。如果它是引用类型,这意味着引用将被复制。

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

https://stackoverflow.com/questions/36602722

复制
相关文章

相似问题

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