【问题标题】:How does `typeof` operator get type argument in generic methods?`typeof` 运算符如何在泛型方法中获取类型参数?
【发布时间】:2019-02-10 05:46:40
【问题描述】:

在 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&lt;T&gt;() 转换为 void Foo(Type T)


更新:

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

ldtoken    !!T
call       System.Type System.Type::GetTypeFromHandle(System.RuntimeTypeHandle)

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

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

【问题讨论】:

标签: c#


【解决方案1】:

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

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

public void Foo<int>() { print(typeof(int)); }

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

【讨论】:

  • 您的最后一点不太正确。 CLR 为每个值类型生成新的运行时方法,但对所有引用类型只生成一个。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-11-15
    • 1970-01-01
    • 2021-06-16
    • 2013-02-03
    • 2015-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多