我为什么不打电话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)
编译器需要专门的类型来专门化泛型方法而Generic<>不是专门的,它是通用的.因此,虽然Generic<>是一种类型,但它并不专门用于泛型方法的专业化.
\n\n\n为什么我不能打电话
\nSomeGenericMethod<SomeGenericType<>>
最简单的答案是:因为语言规范是这样说的:
\n\n\n\n\n\n\n4.4 构造类型
\n\n泛型类型声明本身表示一个未绑定的泛型类型,它用作 \xe2\x80\x9cblueprint\xe2\x80\x9d 通过应用类型参数来形成许多不同的类型。类型参数写在紧跟在泛型类型名称后面的尖括号(< 和 >)内。至少包含一个类型参数的类型称为构造类型。构造类型可以用在可以出现类型名称的语言中的大多数地方。未绑定泛型类型只能在 typeof 表达式 (\xc2\xa77.6.11) 中使用。
\n
\n\n\n4.4.3 绑定和非绑定类型
\n\n术语“未绑定类型”是指非泛型类型或未绑定泛型类型。术语“绑定类型”是指非泛型类型或构造类型。\n“非绑定类型”是指由类型声明声明的实体。未绑定泛型类型本身不是类型,不能用作变量、参数或返回值的类型,也不能用作基类型。可以引用未绑定泛型类型的唯一构造是 typeof 表达式 (\xc2\xa77.6.11)。
\n
为什么 C# 规范这么说?因为CLI 规范也规定了这一点:
\n\n\n\n\nII.9.4 实例化泛型类型
\n\n...
\n\nCLI 不支持泛型类型的部分实例化。并且泛型类型不得在元数据签名 blob 中的任何位置出现未实例化的情况。
\n
好吧,现在让我们停止法律术语。您问题的实际答案是:
\n\n当您SomeMethod<SomeType>()第一次调用时,CLR 将调用 JIT 编译器,该编译器将读取SomeMethod<T>、替换T并创建代表 的新可执行代码SomeMethod<SomeType>。
当您调用 时SomeMethod<SomeOtherType>(),需要重复该过程,将为 生成全新的代码SomeMethod<SomeOtherType>。
您不能只为未绑定的泛型类型(如Generic<>. 在一般情况下,JIT 在不知道的情况下无法知道要生成什么代码表示T。
T是 astring并且您的方法声明了类型为 的局部变量T,则 JIT 将分配堆栈空间或使用具有本机指针大小的寄存器。T是 a Guid,JIT 将必须为固定的 128 位值分配堆栈空间。T如果它不知道会发生什么,它就无法生成代码。因此,一般来说,您无法为未绑定类型生成可执行代码。为什么您可以对您提供的代码片段执行此操作,这将需要特殊情况,并且如果您T在PrintType方法中添加本地代码,您的调用代码将停止工作。由于泛型必须可跨程序集重用,因此调用代码不能假设有关被调用方法的任何信息。