35

I know that ViewData and ViewBag both use the same backing data and that neither are as good as using strongly typed models in most cases. However when choosing between the two is the dynamic nature of ViewBag slower than using ViewData?

Andrei Rînea
  • 20,288
  • 17
  • 117
  • 166
user169867
  • 5,732
  • 10
  • 39
  • 56

2 Answers2

48

Okay - my initial answer basically said 'no' - time for a bit of a u-turn.

It should be 'no' in a perfect dynamic world - but upon closer inspection it would appear that there will either be no difference (accounting for JIT magic) or it might be ever-so-slightly slower, although not enough to warrant not using it (I certainly am).

In theory if properly implemented, the ViewBag would ultimately outperform the use of the ViewData dictionary because the binding of the expressions (e.g. ViewBag.Foo) is very well cached across the different CallSites that the compiler will generate (reflect a method that does a read or write to the ViewBag and you'll see what I mean).

The caching layers of the DLR are well documented (if a little difficult to understand once you get in depth) but basically the runtime does its best to 'remember' where a given value instance is once its bound it - for example via a Set or Get statement.

BUT The caching, its use and effectiveness, is entirely dependent upon the underlying implementations of classes/interfaces such as DynamicObject, IDynamicMetaObjectProvider etc; as well as the end-result of the Get/Set expression binding.

In the case of the MVC internal DynamicViewDataDictionary class - it ultimately ends up binding to this:

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

For var a = ViewBag.Foo

And

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

For ViewBag.Foo = Bar;

In other words - the statements are effectively being rewritten to wrappers around the dictionary indexer.

Because of that, there's certainly no way it could be faster than doing it yourself.

Were ViewData to feed off of ViewBag, instead of the other way around, and had ViewBag then been implemented with even something like ExpandoObject, then it might be a different story - as the dynamic implementation of ExpandoObject is much more intelligent and the caching rules it employs allow for some pretty cool runtime optimisations.

In Conclusion

(thanks to Shawn McLean for suggesting one was needed!)

ViewBag will be slower than ViewData; but probably not enough to warrant concern.

Andras Zoltan
  • 41,961
  • 13
  • 104
  • 160
  • 5
    Could you like...put a conclusion so lazy people like me who just wants to know which is better can just read the last paragraph lol? – Shawn Mclean Apr 27 '11 at 02:04
  • 4
    @Shawn Mclean - lol yeah you're right! Updating my answer :) – Andras Zoltan Apr 27 '11 at 08:17
  • 2
    Something to note that made me look for an answer to this question myself, VS2013 shows a *A first chance exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in Microsoft.CSharp.dll* error when trying to access it in debug. Whether this only happens in debug or normally as part of the process, it is something to consider. ViewData does not throw that. This is when the value does exist. – Tony Basallo Feb 06 '15 at 22:33
  • Yup this is standard procedure for all dynamic code where the dynamic implementation does not find a member with the given name (outside of types which might implement the dynamic interchange themselves through IDynamicMetaObjectProvider) And it's fair to say that this contributes certainly part of the speed difference – Andras Zoltan Feb 10 '15 at 15:58
9

I haven't done any test but my gut feel is that in real world scenarios the difference is just negligible. You will probably access it a few times on each page and a few CPU cycles won't make any difference. One can find bigger performance improvements in other places.

Jakub Konecki
  • 45,581
  • 7
  • 87
  • 126
  • 1
    I agree, it's more of an academic curiosity. – user169867 Feb 22 '11 at 14:03
  • 1
    The only solution here is to write a little test with for(i=0; i<1000000; ++i) – Jakub Konecki Feb 22 '11 at 14:09
  • 1
    @CallMeLaNN - test to difficult for you to do yourself? – Jakub Konecki Mar 07 '11 at 08:54
  • 1
    I its easy but I am not looking for this right now as a serious performance unless someone claim it. Just for info to take into account in future development. If I do the test right now and performance is critical for me, I also want to know result from others since it may varies based on the test algorithm. – CallMeLaNN Mar 12 '11 at 06:09