`typeof`运算符如何在泛型方法中获取类型参数?

yyy*_*yyy 5 c#

在Java中,此代码不起作用:

public <T> void foo() { print(T.class); } // compile time error
Run Code Online (Sandbox Code Playgroud)

因为泛型类型T在运行时被删除.要使用T,我必须使用它作为参数,它将推String.class入堆栈

public <T> void foo(Class<T> T) { print(T); }
public void bar() { foo(String.class); }
Run Code Online (Sandbox Code Playgroud)

但在C#中,我可以在运行时获取类型参数:

public void Foo<T>() { print(typeof(T)); }
Run Code Online (Sandbox Code Playgroud)

它是如何工作的?编译器(或vm)是否自动转换void Foo<T>()void Foo(Type T)


更新:

我反汇编了字节码,得到了类似的东西:

ldtoken    !!T
call       System.Type System.Type::GetTypeFromHandle(System.RuntimeTypeHandle)
Run Code Online (Sandbox Code Playgroud)

由于ldtoken是"将元数据令牌转换为其运行时表示"的指令,因此很明显运行时类型T存储为元数据.

我猜每个方法都有自己的"元数据表"(或类似的东西),所以调用Foo<string>()Foo<object>()生成两个"方法句柄"和两个"元数据表",但共享相同的机器代码.是吗?

Sel*_*enç 5

编译器(或 vm)是否自动将 void Foo() 转换为 void Foo(Type T)?

不,没有。泛型方法的主体是在运行时动态生成的。因此,例如,当您提供Tas时int,会生成此方法:

public void Foo<int>() { print(typeof(int)); }
Run Code Online (Sandbox Code Playgroud)

每次传递不同类型时都会发生这种情况。但是,如果再次使用相同的类型,CLR 将缓存先前生成的方法并执行它,而不是生成新的方法。

  • 你的最后一点不太正确。CLR 为每种值类型生成新的运行时方法,但仅为所有引用类型生成一个新的运行时方法。 (3认同)

nil*_*irk 0

在 .NET 中,泛型不会被删除。CLR 将泛型一直实现到字节码。