MVC中的ViewBag和ViewData性能差异?

35

我知道ViewData和ViewBag都使用相同的后台数据,但在大多数情况下,它们都不如使用强类型模型好。然而,在选择两者之间时,ViewBag的动态特性是否比使用ViewData更慢?

2个回答

48

好的,我的初始答案基本上是“不行”,现在需要做一个大转弯。

在完美动态世界中,理论上应该是“不行”的,但仔细检查后发现,除了考虑 JIT 魔法外,可能不会有任何区别,或者说可能会稍微慢一点点,但不足以不使用它(至少我是这么做的)。

从理论上讲,如果正确地实现,ViewBag 最终将优于使用 ViewData 字典,因为表达式的绑定(例如 ViewBag.Foo)非常好地缓存于编译器生成的不同 CallSite 之间(反射一个读取或写入 ViewBag 的方法,你就会明白我的意思)。

DLR 的缓存层有很好的文档(深入理解起来有点困难),但基本上运行时会尽力“记住”绑定给定值实例的位置,例如通过 Set 或 Get 语句。

但是缓存、它的使用和有效性完全取决于类/接口的底层实现,例如 DynamicObjectIDynamicMetaObjectProvider 等,以及 Get/Set 表达式绑定的最终结果。

在 MVC 内部的 DynamicViewDataDictionary 类中,它最终绑定到此处:

public override bool TryGetMember(GetMemberBinder binder, out object result)
{
  result = this.ViewData[binder.Name];
  return true;
}

对于 var a = ViewBag.Foo

以及

public override bool TrySetMember(SetMemberBinder binder, object value)
{
  this.ViewData[binder.Name] = value;
  return true;
}

对于ViewBag.Foo = Bar;

换句话说 - 这些语句实际上被重写为字典索引器的包装器。

因此,它肯定不能比自己手动执行更快。

如果ViewDataViewBag为基础,并且使用类似ExpandoObject这样的东西来实现ViewBag,那么情况可能会有所不同 - 因为ExpandoObject的动态实现要更加智能,它采用的缓存规则允许进行一些相当不错的运行时优化。

总之

(感谢Shawn McLean建议需要这样一个结论!)

ViewBag会比ViewData慢;但可能不足以引起关注。


5
可以的,你希望我在最后一段加上结论,这样像我这样懒得看整篇内容的人就能只读最后一段了,哈哈? - Shawn Mclean
4
@Shawn Mclean - 哈哈,是的,你说得对!我正在更新我的回答 :) - Andras Zoltan
2
一个需要注意的问题,这让我自己寻找答案,当我试图在调试中访问它时,VS2013会显示 在Microsoft.CSharp.dll中发生了'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException'类型的第一次机会异常 错误。无论这是仅在调试期间发生还是正常作为过程的一部分,都需要考虑这个问题。 ViewData 不会抛出此类异常。这是当值确实存在时的情况。 - Tony Basallo
是的,这是所有动态代码的标准程序,其中动态实现未找到具有给定名称的成员(除了可能通过IDynamicMetaObjectProvider自己实现动态交换的类型之外)。可以说,这肯定是速度差异的一部分。 - Andras Zoltan

9

我没有做过任何测试,但我觉得在实际场景中,这种差异微不足道。你可能每个页面都会访问它几次,而且只有几个CPU周期不会有任何区别。我们可以在其他地方找到更大的性能提升。


1
我同意,这更多是学术上的好奇心。 - user169867
1
这里唯一的解决方案是编写一个简单的测试,使用for(i=0; i<1000000; ++i)。 - Jakub Konecki
1
@CallMeLaNN - 这个测试对你来说太难了吗? - Jakub Konecki
1
这很容易,但我现在不认为它是一个严肃的性能问题,除非有人提出异议。只是提供信息以便将来开发时考虑。如果我现在进行测试并且性能对我至关重要,我也想知道其他人的结果,因为这可能会根据测试算法而有所不同。 - CallMeLaNN

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接