运行时能够区分泛型参数是值类型或是引用类型,即泛型参数是值类型,则查找是否有该值类型的专有版本,如果没有则创建该值类型的专有版本;如果泛型参数是引用类型,则查找是否有引用的专有版本,如果没有则创建引用的专有版本。
学习了~
我问题其实所针对的就是引用类型,《CLR via c#》一书中提到CLR为了规避类型膨胀做了一个优化,为所有引用类型只生成一份nativecode。如果按照这个做法,不可避免的也需要做一次强制类型转换,这不就丧失了真实泛型的性能优势了(或者说这一优化并非是通用的,因为我借助静态泛型的构造函数对每个引用类型执行/转载了一次)。。。比较困惑,想反汇编看看结果。。。
@答案在风中: C++与C#中的泛型的作用是不一样的,因为 C++ 中的类型系统同 C#(CLR) 中的不一样。C++中没有值类型到引用类型的装箱操作,而这正是类型转换的主要开销。不管是在C++还是C#中,泛型类型安全都是在编译时就确定了,因此,到了运行时,强制类型转换并不需要运行时做类型检查就能直接转换,而这个转换几乎是没有成本的。在C#中,引用类型共用泛型模板的专有版本可以极大的减少代码,因为引用总是占有相同大小的内存空间。
因此,C#中对泛型的实现,主要考虑的问题就是区分值类型和引用类型,防止装箱和拆箱操作带来的性能损耗。C++中不用考虑这点,也无法考虑,因为所有类型都没有必然的可转换性。
你可以做个测试,数据是不会说谎的。
@Launcher: 嗯,谢谢
以动态数组为例,在.net 2.0以前,是用System.Collections.ArrayList来表示的,它基本上和Java中的伪泛型是等价的。在.net 2.0后,推出了其泛型版本List<T>
之所以说ArrayList效率低,是因为它的每个成员都是一个object,如果在ArrayList中存放值类型时,会有一个装箱和拆箱的操作,这个效率比较低,因此,List<int>是比存放int类型的ArrayList效率高不少的。
但是,ArrayList的效率低也只是体现在值类型上。如果拿来存放引用类型,就没有装箱和拆箱这个开销了,就算生成了本地代码,List<string>是和存放string类型的ArrayList的性能也是非常接近的。因此,对于引用类型,是没有必要生成一份native code,毕竟工作集增大也是有性能影响的。
如果你有兴趣,大可以自己写一个类似的数据结构比较一下值类型和引用类型在使用object存储和强类型存储时的性能差异。
我问题其实所针对的就是引用类型,《CLR via c#》一书中提到CLR为了规避类型膨胀做了一个优化,为所有引用类型只生成一份nativecode。如果按照这个做法,不可避免的也需要做一次强制类型转换,这不就丧失了真实泛型的性能优势了(或者说这一优化并非是通用的,因为我借助静态泛型的构造函数对每个引用类型执行/转载了一次)。。。比较困惑,想反汇编看看结果。。。
@答案在风中:
引用的类型转换没有装箱和拆箱,又没有什么开销。简单的说,引用类型的非泛型集合本身就非常高效了,就算代码膨胀后生成对应的泛型集合,性能也没有什么大的提升。反而还会因为工作集增大影响性能。