代码改变世界

浅谈 MVC3 中关于 ViewData 和 ViewBag 的区别和联系

2011-11-10 00:03  Michael.青菜  阅读(4073)  评论(5编辑  收藏

我们在用 MVC3 开发网站的时候,Controller 和 View 中经常会用到这两个变量 ViewBag、ViewData,ViewBag 是动态类型(dynamic),ViewData 是一个字典型的(Dictionary)。

一般情况下,我们都知道这两个变量怎么用,但新手们一般都不知道有什么区别和联系(包括我自己也是),前两天跟几位同事一起讨论研究了一下 MCV3 中 ViewData 和 ViewBag 的区别和联系,在此跟各位博友分享一下。

当然鄙人对这两种变量的研究也不是很深入,发布这篇随笔呢,只想抛砖引玉,希望广大的博友都能谈谈对这两种变量的理解。

在用 ViewBag 和 ViewData 的时候,我们可以这样写:

Controller 端:

public ActionResult Index()
{
ViewBag.Hi = "Hi Girl!";
ViewData["Hello"] = "Hello Boy!";

return View();
}

View 端:

@ViewBag.Hi
<br />
@ViewData["Hello"]

输出:

当然,我们也可以这么写:

Controller 端:

public ActionResult Index()
{
ViewBag.Hi = "Hi Girl!";
ViewData["Hello"] = "Hello Boy!";

return View();
}

View 端:

@ViewData["Hi"]<br />
@ViewBag.Hello

输出:

从上面的两个例子我们可以看出,ViewBag 和 ViewData 是互通的,那么他们到底有什么区别呢?

我们可以看到他们的定义:

//
// Summary:
// Gets the dynamic view data dictionary.
//
// Returns:
// The dynamic view data dictionary.
[Dynamic]
public dynamic ViewBag { get; }
//
// Summary:
// Gets or sets the dictionary for view data.
//
// Returns:
// The dictionary for the view data.
public ViewDataDictionary ViewData { get; set; }

从注释来看,ViewBag 是“获取动态视图数据字典。”并没有设置视图数据这一说,而且 ViewBag 也没有 set 方法,而我们在使用的过程中,恰恰是能够进行 set 操作的,这是为什么呢?

ViewData 相对于 ViewBag 更全面,而且支持更多的方法和属性,从下图我们便可看出:

那到底为什么 ViewBag 和 ViewData 的数据能够互通呢, MVC 做了什么操作呢?

我们来分析分析他的源码:

public dynamic ViewBag
{
get
{
if (_dynamicViewDataDictionary == null)
{
_dynamicViewDataDictionary = new DynamicViewDataDictionary(() => ViewData);
}
return _dynamicViewDataDictionary;
}
}

上面这段是 ViewBag 的源码,我们看到 ViewBag 的值是从一个 DynamicViewDataDictionary 的实例中获取的,而这个 DynamicViewDataDictionary 内部是什么样子的呢:

internal sealed class DynamicViewDataDictionary : DynamicObject
{
private readonly Func<ViewDataDictionary> _viewDataThunk;

public DynamicViewDataDictionary(Func<ViewDataDictionary> viewDataThunk)
{
_viewDataThunk = viewDataThunk;
}

private ViewDataDictionary ViewData
{
get
{
ViewDataDictionary viewData = _viewDataThunk();
Debug.Assert(viewData != null);
return viewData;
}
}

// Implementing this function improves the debugging experience as it provides the debugger with the list of all
// the properties currently defined on the object
public override IEnumerable<string> GetDynamicMemberNames()
{
return ViewData.Keys;
}

public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = ViewData[binder.Name];
// since ViewDataDictionary always returns a result even if the key does not exist, always return true
return true;
}

public override bool TrySetMember(SetMemberBinder binder, object value)
{
ViewData[binder.Name] = value;
// you can always set a key in the dictionary so return true
return true;
}
}

上面这段就是 DynamicViewDataDictionary 的类的源码了,相信大家看了自然了解了 ViewBag 和 ViewData 的异同了,而且 TrySetMember 方法也解释了,为什么 ViewBag 只有 set 方法却可以赋值的原因。

上面这些都是鄙人对这两种变量的理解和认识,若有任何不足或者不对之处欢迎大侠们指出!