为什么通用类型在 CIL 中的函数定义处看起来像 (!!T)

Why is the generic type looks like (!!T) at function definition in CIL

为什么在 CIL 中泛型在函数定义处看起来像 (!!T) 而在调用者处看起来像 (!!0)。在某些情况下,泛型类型的参数看起来像 (!0)。背后的秘密是什么?或者为什么要这样设计?

提前致谢。

以下是 C# 中的代码:

    private static void Main(string[] args)
    {
        Test<int>();
        TestList<int>(new List<int>{ 1, 2,3 }, 1, 2, 3, 4, 5, 6, 7,8);
        Console.ReadKey();
    }

    private static void TestList<T>(List<T> list, T item, T t2, T t3, T t4, T t5, T t6, T t7, int t8)
    {
        Console.WriteLine(item == null);
        Console.WriteLine("Collection contains {0}? {1}",  item, list.Contains(item));
    }

以及调用TestList的CIL代码:

IL_002e:  call       void BoxingAndUnboxing.Program::TestList<int32>(class        [mscorlib]System.Collections.Generic.List`1<!!0>,
                                                                   !!0,
                                                                   !!0,
                                                                   !!0,
                                                                   !!0,
                                                                   !!0,
                                                                   !!0,
                                                                   !!0,
                                                                   int32)

及函数定义的CIL代码:

.method private hidebysig static void  TestList<T>(class [mscorlib]System.Collections.Generic.List`1<!!T> list,
                                               !!T item,
                                               !!T t2,
                                               !!T t3,
                                               !!T t4,
                                               !!T t5,
                                               !!T t6,
                                               !!T t7,
                                               int32 t8) cil managed

以及显示类型为!0而不是!!0的CIL代码

 IL_001d:  callvirt   instance bool class [mscorlib]System.Collections.Generic.List`1<!!T>::Contains(!0)

!0表示包含class.
的第一个泛型参数 !!0表示方法本身的第一个泛型参数。

class C<X> { void M<Y>(X a, Y b) {} } 中的方法将被称为 C`1::M`1(!0, !!0)!0X!!0Y

最后,!!0,用于引用方法时,表示方法声明的第一个参数,而!!T,用于实际实现时,表示当前方法的类型参数名为 T.

!!0 在方法引用中是必要的,以区分 M<X, Y>(X x, Y y)M<X, Y>(Y y, X x),它们变成 M`2(!!0, !!1)M`2(!!1, !!0).