现在的位置: 首页 > 综合 > 正文

[Programming IL]泛型, Generic Types

2011年10月24日 ⁄ 综合 ⁄ 共 4727字 ⁄ 字号 评论关闭
文章目录

引言:

自从泛型那天诞生起,广大的面向对象程序员对于他的热爱普遍要高于其他数据结构. :). 然而各大面向对象对于他的支持却不太一样。在CPP中用的是静态编译,即在编译器决定泛型的类型,而.Net则是在运行时确定,他们有什么不一样呢?

和周围的同事谈起泛型,发现大伙对于这东西都是似懂非懂,觉得自己有必要作一次应用总结了. :( , 由于范型内容较多,请看这里:

我们从C#总定义一段基本的范型代码开始

   1: public class GenericType<T> : IComparable<T>, IComparable<GenericType<T>>
   2:                     where T: IComparable
   3: {
   4:     public T Value;
   5:     
   6:     public int CompareTo(T t)
   7:     {
   8:         return this.Value.CompareTo(t);
   9:     }
  10:     
  11:     public int CompareTo(GenericType<T> t)
  12:     {
  13:         return this.Value.CompareTo(t.Value);
  14:     }
  15: }

反编译后的IL代码

   1: .class public auto ansi beforefieldinit GenericType`1<([mscorlib]System.IComparable) T>
   2:        extends [mscorlib]System.Object
   3:        implements class [mscorlib]System.IComparable`1<!T>,
   4:                   class [mscorlib]System.IComparable`1<class GenericType`1<!T>>
   5: {
   6:   .field public !T Value
   7:   .method public hidebysig newslot virtual final 
   8:           instance int32  CompareTo(!T t) cil managed
   9:   {
  10:     // Code size       24 (0x18)
  11:     .maxstack  8
  12:     IL_0000:  ldarg.0
  13:     IL_0001:  ldflda     !0 class GenericType`1<!T>::Value
  14:     IL_0006:  ldarg.1
  15:     IL_0007:  box        !T
  16:     IL_000c:  constrained. !T
  17:     IL_0012:  callvirt   instance int32 [mscorlib]System.IComparable::CompareTo(object)
  18:     IL_0017:  ret
  19:   } // end of method GenericType`1::CompareTo
  20:  
  21:   .method public hidebysig newslot virtual final 
  22:           instance int32  CompareTo(class GenericType`1<!T> t) cil managed
  23:   {
  24:     // Code size       29 (0x1d)
  25:     .maxstack  8
  26:     IL_0000:  ldarg.0
  27:     IL_0001:  ldflda     !0 class GenericType`1<!T>::Value
  28:     IL_0006:  ldarg.1
  29:     IL_0007:  ldfld      !0 class GenericType`1<!T>::Value
  30:     IL_000c:  box        !T
  31:     IL_0011:  constrained. !T
  32:     IL_0017:  callvirt   instance int32 [mscorlib]System.IComparable::CompareTo(object)
  33:     IL_001c:  ret
  34:   } // end of method GenericType`1::CompareTo
  35:  
  36:   .method public hidebysig specialname rtspecialname 
  37:           instance void  .ctor() cil managed
  38:   {
  39:     // Code size       7 (0x7)
  40:     .maxstack  8
  41:     IL_0000:  ldarg.0
  42:     IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
  43:     IL_0006:  ret
  44:   } // end of method GenericType`1::.ctor
  45:  
  46: } // end of class GenericType`1

我们将之拆解为几个简单的部分来讨论

1. 定义一个泛型类

   这个部分又大可以分拆为

  •   声明一个类
       1: .class public GenericType <([mscorlib]System.IComparable) T>
       2:     extends [mscorlib]System.Object
       3:     implements class [mscorlib]System.IComparable<!T>
       4:                class [mscorlib]System.IComparable<class GenericType<T>> 
       5: {
       6: }

与声明一个非泛型类而言不同的就是

       1: <([mscorlib]System.IComparable) T>
  •   声明变量
       1: .class public value Pair<T>
       2: {
       3:     .field public !T x
       4:     .field public !T y    // fields x and y have the same type T
       5: }
  •   声明方法
       1: .class public List`1<T>
       2: {
       3:     .method public void Append(!T val) { ... }
       4:     .method public !T GetLast() { ... }
       5:     //...
       6: }
  •   隐藏与覆盖

这个部分,泛型的实现与非泛型一致,我们可以查看一个实例

我们为之前定义的GenericType定义两个方法

   1: public void BaseRun()
   2: {
   3:     Console.WriteLine("This is the base Run");
   4: }
   5:  
   6: public virtual void ParentMethod()
   7: {
   8:     Console.WriteLine("The is the parentVirtual Method");
   9: }

再为他定义一个基类DerivedClass

   1: public class DerivedClass<T> : GenericType<T> 
   2:             where T : IComparable
   3: {
   4:     public new void BaseRun()
   5:     {
   6:         Console.WriteLine("This is the derived class running");
   7:     }
   8:     
   9:     public override void ParentMethod()
  10:     {
  11:         Console.WriteLine("This is the derived class");
  12:     }
  13: }

对比下生成的IL代码

   1: .method public hidebysig instance void  BaseRun() cil managed
   2: {
   3:   // Code size       11 (0xb)
   4:   .maxstack  8
   5:   IL_0000:  ldstr      "This is the derived class running"
   6:   IL_0005:  call       void [mscorlib]System.Console::WriteLine(string)
   7:   IL_000a:  ret
   8: } // end of method DerivedClass`1::BaseRun
   9:  
  10: .method public hidebysig virtual instance void 
  11:         ParentMethod() cil managed
  12: {
  13:   // Code size       11 (0xb)
  14:   .maxstack  8
  15:   IL_0000:  ldstr      "This is the derived class"
  16:   IL_0005:  call       void [mscorlib]System.Console::WriteLine(string)
  17:   IL_000a:  ret
  18: } // end of method DerivedClass`1::ParentMethod

 

2. 定义约束

参考之前提到的几种约束,我们分别用IL来做一下解释

  • 值类型约束

       1: .class public ClassType`1<valuetype .ctor ([mscorlib]System.ValueType) T>
       2:        extends [mscorlib]System.Object
       3: {}
  • 引用类型约束
       1: .class public ClassType`1<class T> extends [mscorlib]System.Object
  • 接口类型约束
  • 参考本文前面的代码
  • 基类约束
       1: .class public BaseClass`1<(class GenericType`1<!T>, [mscorlib]System.IComparable) T>
       2:        extends [mscorlib]System.Object
  • 无参构造函数约束
       1: .class public auto ansi beforefieldinit CtorType`1<.ctor T>
       2:        extends [mscorlib]System.Object
  • 多个泛型类型关系约束
       1: .class public ParentChild`2<T, (!T)U> // U must bedescendant of T
       2: {
       3:     //TODO:: Implement this ...
       4: }
  • (!T)U代表了U必须是可以通过类型转换变成T,即U为T的子类
  • 来个复杂点的
   1: .class public auto ansi beforefieldinit ComplexType`1<class .ctor ([mscorlib]System.IComparable) T>
   2:        extends [mscorlib]System.Object

可以看到,几种类型定义的不同只存在于 <类型定义>

走到这里,我还是不明白,虽然在IL层次上的东西做的相当的简洁,那泛型那些优势又是如何实现的呢,去看了下元数据定义也没啥惊喜

元数据定义:

Generic Param(泛型参数), 即<类型定义>:

GenericParam Metadata Table:

名称 作用

Number(2-byte unsigned integer).

泛型类型中泛型参数的位置

Flags(2-byte bit field).

代表泛型约束

Owner(coded token of type TypeOrMethodDef).

泛型参数所对应的泛型类型

Name(offset in the #Strings stream).

泛型参数名称

Generic Method(泛型方法):

   1: <gen_method_def> ::=
   2: .method <flags> <call_conv> <ret_type> <name>< <gen_params> > (<arg_list>) <impl>
   3: { <method_body> }
   4: For example:
   5: .method public static !!T GetMedian<T>(!!T[] tarray)
   6: {
   7:     ldarg.0
   8:     dup
   9:     ldlen
  10:     ldc.i4.1
  11:     shr
  12:     ldelem !!T
  13:     ret
  14: }

关于CLR对于运行时创建好像很难找到相关资料,有待进一步深入了 :), 本文断断续续也写了很久了,先画上一个句号吧

参考

  • Expert IL Assembler 2.0
  • Professional.Net 2.0 Generic
  • ECMA Partion II

抱歉!评论已关闭.