在Java中,此代码不起作用:
public <T> void foo() { print(T.class); } // compile time error
因为通用类型T
在运行时被删除。要使用T
,我必须将其用作参数,这会将String.class
推入堆栈
public <T> void foo(Class<T> T) { print(T); }
public void bar() { foo(String.class); }
但是在C#中,我可以在运行时获取类型参数:
public void Foo<T>() { print(typeof(T)); }
它如何工作?编译器(或vm)是否自动将void Foo<T>()
转换为void Foo(Type T)
?
更新:
我反汇编了字节码,并得到了类似的内容:
ldtoken !!T
call System.Type System.Type::GetTypeFromHandle(System.RuntimeTypeHandle)
由于ldtoken
是一条“将元数据令牌转换为其运行时表示形式的指令”,因此很明显T
的运行时类型将存储为元数据。
我猜每个方法都有它自己的“元数据表”(或类似的东西),因此调用Foo<string>()
和Foo<object>()
将生成两个“方法句柄”和两个“元数据表”,但是共享相同的机器代码。是吗?
答案 0 :(得分:4)
编译器(或vm)会自动将void Foo()转换为void Foo(Type T)吗?
不,不是。泛型方法的主体是在运行时动态生成的。因此,例如,当您提供T
作为int
时,将生成此方法:
public void Foo<int>() { print(typeof(int)); }
每次您传递不同的类型都会发生这种情况。但是,如果再次使用同一类型,则CLR将缓存先前生成的方法并执行它,而不是生成新的方法。
答案 1 :(得分:0)
在.NET中,不会删除泛型。 CLR从头到尾都实现了泛型。