最近我尝试使用泛型实现编译时调度(下面的示例)
public interface IAbstraction
{
public void Initialize();
}
public sealed class Implementation : IAbstraction
{
public void Initialize()
{
}
}
public sealed class GenericUsage<T> where T : class, IAbstraction
{
private readonly T _abstraction;
public GenericUsage(T abstraction)
{
_abstraction = abstraction;
}
public void CallAction()
{
_abstraction.Initialize();
}
}
public static void Main()
{
var genericUsage = new GenericUsage<Implementation>(new Implementation());
genericUsage.CallAction();
}
如您所见,我还明确使用
sealed
关键字作为信号,表明传递给构造函数的类型不可能与 Generic 中使用的类型不同。
在 JIT Asm 方面,我没有看到去虚拟化。呼叫仍在通过 vtable 进行。
是否有机会通过泛型实现编译时调度?也许我错过了一些东西。如果没有,为什么上面的例子不起作用?
有一个 2015 open 问题与您尝试实现的目标非常相似: RyuJIT 调用优化和已知泛型类型的积极内联
来自评论(2018):
对于通过引用类型实例化的泛型,我们不太可能这样做 很快就会实现去虚拟化,因为 jit 只能看到共享的 版本。如果我们以某种方式启用的话,这可能会在未来发生变化 未共享的引用类型实例化或开始研究推测 去虚拟化。
“共享版本”在共享泛型设计
中有更好的解释这个想法是,对于某些实例化,生成的代码将 除了一些指令之外几乎相同,所以在 为了减少内存占用以及我们花费的时间 jitting这些通用方法,运行时将生成一个单一的 代码的特殊规范版本,可供所有人使用 该方法的兼容实例。
此功能目前仅支持实例化 引用类型,因为它们都有相同的 大小/属性/布局/等等...用于基本类型的实例化 或值类型,运行时将为它们生成单独的代码体 每个实例化。