美文网首页
.Net IL语言如何定义带参数的泛型类型

.Net IL语言如何定义带参数的泛型类型

作者: Brent姜 | 来源:发表于2017-08-01 09:53 被阅读63次

参考TypeBuilder.DefineGenericParameters Method,有很完整的代码和描述。

这个例子中做的事情是:

  • 定义一个动态程序集(DynamicAssembly),

      // Define a dynamic assembly to contain the sample type. The
      // assembly will not be run, but only saved to disk, so
      // AssemblyBuilderAccess.Save is specified.
      //
      AppDomain myDomain = AppDomain.CurrentDomain;
      AssemblyName myAsmName = new AssemblyName("GenericEmitExample1");
      AssemblyBuilder myAssembly = 
          myDomain.DefineDynamicAssembly(myAsmName, 
              AssemblyBuilderAccess.RunAndSave);
    
  • 动态程序集由多个可执行模块组成。对于只有一个可执行模块的程序集,模块名称应该和程序集名称一致。

      // An assembly is made up of executable modules. For a single-
      // module assembly, the module name and file name are the same 
      // as the assembly name. 
      //
      ModuleBuilder myModule = 
          myAssembly.DefineDynamicModule(myAsmName.Name, 
             myAsmName.Name + ".dll");
    

需要用到GenericTypeParameterBuilder 。

最终得到的MSIL代码是:

    .method public static class [mscorlib]System.Collections.Generic.List`1<!TFirst> 
            ExampleMethod(!TFirst[] A_0) cil managed
    {
      // 代码大小       7 (0x7)
      .maxstack  2
      IL_0000:  ldarg.0
      IL_0001:  newobj     instance void class [mscorlib]System.Collections.Generic.List`1<!TFirst>::.ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1<!0>)
      IL_0006:  ret
    } // end of method Sample::ExampleMethod

其中!0的解释参考Why is !0 a type in Microsoft Intermediate Language (MSIL)?,You need to read !n as the n-th type argument of the generic type. Where !0 means "first type argument", !1 means "second type argument", etcetera. For Nullable<>, you know that '!0` means 'T' from the MSDN article。

如果直接写C#类和函数:

    public class MyClass
    {
        public static List<TFirst> ExampleMethod<TFirst>(TFirst[] A_0)
        {
            return new List<TFirst>(A_0);
        }
    }

得到的MSIL代码是:

    .method public hidebysig static class [mscorlib]System.Collections.Generic.List`1<!!T> 
            ExampleMethod<T>(!!T[]& A_0) cil managed
    {
      // 代码大小       13 (0xd)
      .maxstack  1
      .locals init ([0] class [mscorlib]System.Collections.Generic.List`1<!!T> V_0)
      IL_0000:  nop
      IL_0001:  ldarg.0
      IL_0002:  ldind.ref
      IL_0003:  newobj     instance void class [mscorlib]System.Collections.Generic.List`1<!!T>::.ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1<!0>)
      IL_0008:  stloc.0
      IL_0009:  br.s       IL_000b
      IL_000b:  ldloc.0
      IL_000c:  ret
    } // end of method MyClass::ExampleMethod

注意前一个代码中是“!TFirst”,这里是“!!T”.两个”!!“(Two exclamation marks),indicate a type argument for a generic method.

MyClass重新定义如下:

    public class MyClass<TFirst>
    {
        public static List<TFirst> ExampleMethod(TFirst[] A_0)
        {
            return new List<TFirst>(A_0);
        }
    }

得到的MSIL代码就和IL动态生成的代码基本一致了(没有两个!!):

    .method public hidebysig static class [mscorlib]System.Collections.Generic.List`1<!TFirst> 
            ExampleMethod(!TFirst[] A_0) cil managed
    {
      // 代码大小       12 (0xc)
      .maxstack  1
      .locals init ([0] class [mscorlib]System.Collections.Generic.List`1<!TFirst> V_0)
      IL_0000:  nop
      IL_0001:  ldarg.0
      IL_0002:  newobj     instance void class [mscorlib]System.Collections.Generic.List`1<!TFirst>::.ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1<!0>)
      IL_0007:  stloc.0
      IL_0008:  br.s       IL_000a
      IL_000a:  ldloc.0
      IL_000b:  ret
    } // end of method MyClass`1::ExampleMethod

也就是说,如果是模板类,选择类型的时候就是一个叹号。如果是模板函数,使用两个叹号。

多出来的几句IL_0007、IL_0008、IL_000a,”br.s“表示“Unconditionally transfers control to a target instruction (short form).” 这几句代码是为了调试时使用的,参考Why is the 'br.s' IL opcode used in this case?。所以换成Release模式编译,就得到了这样的MSIL代码:

    .method public hidebysig static class [mscorlib]System.Collections.Generic.List`1<!TFirst> 
            ExampleMethod(!TFirst[] A_0) cil managed
    {
      // 代码大小       7 (0x7)
      .maxstack  8
      IL_0000:  ldarg.0
      IL_0001:  newobj     instance void class [mscorlib]System.Collections.Generic.List`1<!TFirst>::.ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1<!0>)
      IL_0006:  ret
    } // end of method MyClass`1::ExampleMethod

这就与IL动态生成代码基本一致了,除了“hidebysig”,它是表示“hide-by-signature”,即如果子类中方法签名与父类方法完全一致,才会覆盖父类方法。这区别月“hide-by-name”。如何在C#中编写代码不使用hidebysig呢?尚未得知……

相关文章

  • .Net IL语言如何定义带参数的泛型类型

    参考TypeBuilder.DefineGenericParameters Method,有很完整的代码和描述。 ...

  • go 泛型

    go 泛型 1. 类型参数(Type parameters) Go语言的泛型(Generic)叫做类型参数。泛型可...

  • java基础-泛型

    一、泛型的定义 泛型:把数据类型当作参数一样来传递。所以也叫参数化类型; 二、泛型的使用场景 泛型集合把泛型定义在...

  • Java泛型

    泛型的概念 泛型就是参数化类型。定义一个带参数的方法时有形参,调用这个方法的时候要传入实参。而所谓参数化类型就是这...

  • javaSE - 008 - 泛型

    泛型 定义:变量类型的参数化。

  • spring 泛型处理

    java 泛型基础 泛型类型:泛型类型是在类型上参数化的泛型类或接口 泛型使用场景编译时前类型检查。定义为 Col...

  • Java中的泛型

    一 泛型是什么泛型最精准的定义:参数化类型。具体点说就是处理的数据类型不是固定的,而是可以作为参数传入。定义泛型类...

  • Java 泛型

    一 泛型概念 泛型,即“参数化类型” 将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数...

  • 四、Java高级--1、泛型

    泛型定义:数据类型参数化,提前定义好集合中放入什么类型集合框架中没使用泛型和使用泛型的比较 泛型规则和限制1、泛型...

  • Kotlin 中的泛型介绍

    泛型类型参数 泛型允许你定义带类型形参的类型。当这种类型的实例被创建出来的时候,类型形参被替换成称为类型实参的具体...

网友评论

      本文标题:.Net IL语言如何定义带参数的泛型类型

      本文链接:https://www.haomeiwen.com/subject/rgndlxtx.html