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

2017-08-01  本文已影响63人  Brent姜

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

这个例子中做的事情是:

需要用到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呢?尚未得知……

上一篇下一篇

猜你喜欢

热点阅读