如何将泛型类型传递给泛型方法?

tal*_*les 12 c# generics

我为什么不打电话SomeGenericMethod<SomeGenericType<>>

class NotGeneric { }

class Generic<T> { }

class Program
{
    static void Main(string[] args)
    {
        PrintType(typeof(NotGeneric));
        PrintType(typeof(Generic<>));
        PrintType<NotGeneric>();
        PrintType<Generic<>>(); // compiler goes crazy here
    }

    static void PrintType<T>()
    {
        Console.WriteLine(typeof(T));
    }

    static void PrintType(Type t)
    {
        Console.WriteLine(t);
    }
}
Run Code Online (Sandbox Code Playgroud)

Ria*_*nli 7

编译器需要专门的类型来专门化泛型方法而Generic<>不是专门的,它是通用的.因此,虽然Generic<>是一种类型,但它并不专门用于泛型方法的专业化.

  • 正如我所写,'Generic <>'是一种类型,因此'typeof(Generic <>)'没有问题.它是通用类型.但泛型类型不能用于专业化,因为它们本身并不专门化. (3认同)

Luc*_*ski 4

\n

为什么我不能打电话SomeGenericMethod<SomeGenericType<>>

\n
\n\n

最简单的答案是:因为语言规范是这样说的:

\n\n
\n

4.4 构造类型

\n\n

泛型类型声明本身表示一个未绑定的泛型类型,它用作 \xe2\x80\x9cblueprint\xe2\x80\x9d 通过应用类型参数来形成许多不同的类型。类型参数写在紧跟在泛型类型名称后面的尖括号(< 和 >)内。至少包含一个类型参数的类型称为构造类型。构造类型可以用在可以出现类型名称的语言中的大多数地方。未绑定泛型类型只能在 typeof 表达式 (\xc2\xa77.6.11) 中使用。

\n
\n\n\n\n
\n

4.4.3 绑定和非绑定类型

\n\n

术语“未绑定类型”是指非泛型类型或未绑定泛型类型。术语“绑定类型”是指非泛型类型或构造类型。\n“非绑定类型”是指由类型声明声明的实体。未绑定泛型类型本身不是类型,不能用作变量、参数或返回值的类型,也不能用作基类型。可以引用未绑定泛型类型的唯一构造是 typeof 表达式 (\xc2\xa77.6.11)。

\n
\n\n

为什么 C# 规范这么说?因为CLI 规范也规定了这一点:

\n\n
\n

II.9.4 实例化泛型类型

\n\n

...

\n\n

CLI 不支持泛型类型的部分实例化。并且泛型类型不得在元数据签名 blob 中的任何位置出现未实例化的情况。

\n
\n\n

好吧,现在让我们停止法律术语。您问题的实际答案是:

\n\n

当您SomeMethod<SomeType>()第一次调用时,CLR 将调用 JIT 编译器,该编译器将读取SomeMethod<T>、替换T创建代表 的新可执行代码SomeMethod<SomeType>

\n\n

当您调用 时SomeMethod<SomeOtherType>(),需要重复该过程,将为 生成全新的代码SomeMethod<SomeOtherType>

\n\n

您不能只为未绑定的泛型类型(如Generic<>. 在一般情况下,JIT 在不知道的情况下无法知道要生成什么代码表示T

\n\n
    \n
  • 如果T是 astring并且您的方法声明了类型为 的局部变量T,则 JIT 将分配堆栈空间或使用具有本机指针大小的寄存器。
  • \n
  • 如果T是 a Guid,JIT 将必须为固定的 128 位值分配堆栈空间。T如果它不知道会发生什么,它就无法生成代码。
  • \n
\n\n

因此,一般来说,您无法为未绑定类型生成可执行代码。为什么您可以对您提供的代码片段执行此操作,这将需要特殊情况,并且如果您TPrintType方法中添加本地代码,您的调用代码将停止工作。由于泛型必须可跨程序集重用,因此调用代码不能假设有关被调用方法的任何信息。

\n