2010-01-26 29 views
2

我一直在考虑是否可以应用DI模式而不会产生虚拟方法调用的代价(根据实验,我的确可以比非虚拟调用慢4倍)。我的第一个想法是通过仿制药做的依赖注入:.Net中的依赖注入没有虚拟方法调用?

sealed class ComponentA<TComponentB, TComponentC> : IComponentA 
    where TComponentB : IComponentB 
    where TComponentC : IComponentC 
{ ... } 

不幸的是,CLR仍然没有方法通过即使TComponentB和TComponentC的具体实现指定为泛型类型参数,所有的类都是接口调用宣布为密封。获得CLR执行非虚拟调用的唯一方法是将所有类更改为结构(实现接口)。使用结构对于DI来说并不合适,并且使得下面的问题更加无法解决。

上述解决方案的第二个问题是它无法处理循环引用。我无法想出任何方法,无论是通过C#代码还是通过构建表达式树来处理循环引用,因为这会导致无限递归泛型类型。 (.Net不支持引用自身的泛型类型,但似乎并没有推广到这种情况。)由于只有结构可以导致CLR绕过接口,所以我认为这个问题根本不可解,因为循环引用结构可能会导致矛盾。

我只能想到其他解决方案,它可以保证工作 - 在运行时从头开始放置所有类,也许将它们作为模板以编译类为基础。虽然不是一个理想的解决方案。

任何人有更好的点子?

编辑:关于大多数评论,我想我应该说这是在“纯粹的知识分子好奇心”下提出的,我辩论是否问这个问题是因为我意识到我没有任何具体的案例,这是必要的。我只是为了好玩而思考它,并想知道是否有其他人遇到过。

+6

慢4倍?我觉得很难相信。我想这个文件“过早优化”下... – BFree 2010-01-26 18:53:16

+0

这是一个个人的,无期限的项目,所以我得到了过早的优化沉迷:) – jthg 2010-01-26 18:56:21

+0

@jthg - 过早的优化可以伤害的不仅仅是最后期限了。 – 2010-01-26 18:58:20

回答

2

虽然callvirt指令确实需要更长的时间,但通常会这样做,因为它在调用方法之前为CLR提供便宜的null检查。 A callvirt不应该比call指令长得多,特别是考虑到null检查。

你有没有发现,你可以显著提高应用程序的创建类型(无论是structs或类的静态方法),让您保证C#编译器会发出指令call而不是callvirt指令的性能?

我问的原因是我想知道是否要创建一个难以维护的代码库,这个代码库很脆弱,很难用于解决可能存在或可能不存在的问题。

+0

是的,使用结构确实减少了开销几乎没有。我想我可能会错误地解释改善的原因。 – jthg 2010-01-26 18:58:28

+0

使用结构也可以减少内存压力,但是它们优化模型化问题域的能力有限。 – 2010-01-26 19:07:09

4

在我看来,试图完全过度设计某些东西的典型例子。只要不要妥协你的设计,因为你可以节省几十毫秒 - 如果它甚至是。

你认真地暗示,因为callvirt的说明,您的应用程序最终被如此显著较慢的用户(那些你写的应用程序的人)会发现任何区别 - 呢?我非常怀疑。

3

这个blog post解释了为什么你不能优化虚拟呼叫。

+0

这是一个很好的解释。谢谢。 – jthg 2010-01-26 19:54:26