美文网首页
.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语言如何定义带参数的泛型类型

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