2011-04-28 38 views
7

在调试View时遇到了一个有趣的效果。该场景很容易重现 - 我在View中有一个断点,在Watch窗口中我添加了ViewBag.ViewData,值为null。但是,如果我只是添加ViewBag并展开对象,则可以看到ViewData,而不是null。我也可以成功扩展它并查看它的属性。我的ViewData如何可以为null,但在调试器中可扩展?

任何人都可以解释是否它是一个错误或导致此行为的原因?

ViewBag.ViewData in Watch window

编辑

ViewBag.ViewData实际上是null。例如。如果我在视图中有这样的代码:

if (ViewBag.ViewData == null) 
{ 
    <span>ViewBag.ViewData is null</span> 
} 

它显示跨度。所以奇怪的部分是我可以在观察窗口中展开它并查看属性。

EDIT2

针对@Darin季米特洛夫的答案 - 我试图重现一个自定义的测试类这种行为,我得到一个RuntimeBinderException试图访问私有财产时:'SomeClass.SomeProperty' is inaccessible due to its protection level

public class SomeClass 
{ 
    private string SomeProperty; 
} 

dynamic dynamicObject = new SomeClass(); 
if (dynamicObject.SomeProperty == null) 
{ 
    Console.WriteLine("dynamicObject.SomeProperty is null"); 
} 

在这种情况下,在视图(if (ViewBag.ViewData == null)的行中)中访问ViewBag.ViewData时,我是不是应该得到相同的异常?

回答

6

你在调试器/监视窗口看到的是ViewBag私人ViewData财产。当您在视图中进行测试时,您显然无法访问此专用字段,并且由于没有相应的公共属性而会得到空值。

现在做如下测试中的观点:

@if (null == ViewBag 
     .GetType() 
     .GetProperty("ViewData", BindingFlags.Instance | BindingFlags.NonPublic) 
     .GetValue(ViewBag, null) 
) 
{ 
    <span>ViewBag.ViewData is null</span> 
} 

,你不会看到的跨度。

当然,这一切都很有趣,但是在编写真实世界和正确架构的ASP.NET MVC应用程序时,ViewDataViewBag都没有位置。这两个是我在ASP.NET MVC应用程序开发中最糟糕的敌人。

结论:总是使用视图模型和强类型视图,玩得开心。

+0

感谢您的回答,它似乎是目前为止似乎最合理的解释(除了Watch/Debugger中的错误)。但是,当我尝试访问'ViewBag.ViewData'(请参阅** EDIT2 **到我的问题)时,我不应该得到'RuntimeBinderException'而不是'null'?顺便说一句,我很感激你提醒ViewBag和ViewData的邪恶,但这不是必要的 - 我自己强烈支持强类型的视图模型;) – Yakimych 2011-04-28 22:07:04

+0

@Yakimych,你的EDIT2并不符合ASP.NET中的真实情况MVC。看看框架的源代码。你会发现从'DynamicObject'派生出来的'System.Web.Mvc.DynamicViewDataDictionary'类型,并且覆盖ViewBag所具有的获取和设置属性。在EDIT2中,您只需将动态值设置为“SomeClass”。我建议你下载并探索ASP.NET MVC的源代码,以深入理解内部运作。 – 2011-04-28 22:15:01

+0

是的,正好 - 当您发布此评论时,我正在查看源代码。 'DynamicViewDataDictionary'继承'DynamicObject'并通过覆盖'TryGetMember'和'TrySetMember'来覆盖默认的'dynamic'行为。没有深入细节,但这最终是有道理的。感谢您满足我的好奇心! +1并接受答案! – Yakimych 2011-04-28 22:29:24

0

我没有技术上的解释,但我相信这是因为ViewBag是动态的。 这就像在一个表达式上执行监视一样,在没有运行表达式的情况下,您看不到结果集的内容。

我猜ViewBag的行为方式是一样的,因为你直接去了一个尚未加载的属性,而你通过调试器来做它,它只是决定不加载该属性。

我可能是完全错误的,当然:d

为了讨论,它做的快手表或即时窗口一样吗?

+0

不,看起来'ViewBag.ViewData'实际上是'null'(查看更新后的问题)。奇怪的部分是为什么我可以在观察窗口中扩展它。 – Yakimych 2011-04-28 12:44:26

0

当你的代码总是在一定范围(类,方法,私有等)的范围内运行,调试器没有这些限制

0

你为什么引用ViewBag.ViewData?只需直接引用ViewData。 这可能会工作,因为幕后viewbag使用viewdata你可能正在看ViewData的内部表示,分开比你的dynamimed属性的“ViewData”

经过测试后,ViewBag显示为非公开成员...这是我所期望的。 System.Web.Mvc.DynamicViewDataDictionary具有非公共成员的ViewData

+0

首先,我没有引用'ViewBag.ViewData' - 正如我在我的问题中提到的那样,我刚刚遇到了这个奇怪的情况,并且有兴趣知道它是一个错误还是动态对象的一些模糊特征。其次,你可否详细说明一下这个问题:'这可能会起作用,因为幕后视图包使用viewdata,你可能正在查看ViewData的内部表示,与你的“ViewData”的dynamimc属性分开。我不确定这是否是标点符号,但我无法理解这一行的想法;) – Yakimych 2011-04-28 22:12:09

+0

最后:'ViewBag作为非公开成员显示......这是我所期望的。 System.Web.Mvc.DynamicViewDataDictionary有一个非公共成员ViewData' - 这是真的,有点合理(也见@Darin Dimitrov的答案),但是当我尝试访问ViewBag.ViewData时,我应该没有得到'RuntimeBinderException' 'null'(见我* EDIT2 *的问题)? – Yakimych 2011-04-28 22:13:36

+0

我只是意味着Darrin在我后面发布的同样的东西..我只是没有说出来:) – 2011-05-04 04:09:48

相关问题