我正在使用Contoso大学教程并尝试模块化尝试(模型,DAL和WebUI的单独项目 - 附图中的顶部图片)和单个项目(包含所有图层 - 底部图片)。在这两种情况下,解决方案都可以正确编译。但是,当我在Web浏览器中转到学生的详细信息部分时,模块化项目在我转到第二个断点时会引发错误,开始:
异常详细信息:
System.NullReferenceException:未将对象引用设置为对象的实例。
将相同的模型传递到每个项目的视图中,
@model ContosoUniversity.Models.Student
在行之后出现空引用异常:
@foreach (var item in Model.Enrollments){
我认为它可能是ContosoUniversity.Models
项目和ContosoUniversity项目中的Models文件夹之间的命名空间冲突,但重命名文件夹无法解决此问题。是否存在与多个项目相关的其他内容会导致在此处遇到空值(Enrollments.cs未发送到模型),而不是单个项目?
如果它在代码中更深层次,我可以跟进完整的视图代码和模型类。
Screenshot of working and non working solutions in VS2015Community
答案 0 :(得分:3)
由于这对新开发人员来说是一个常常令人困惑的错误,我已经创作了一个post on my blog来解释错误的含义以及如何调试它。 TL; DR:Object reference not set to an instance of an object
是一个运行时错误(因此你的项目编译好的原因),当你期望一个变量成为一个特定类的实例时,它就会发生,但它实际上在运行时解析为null。
这通常发生在您从数据库中选择对象但没有匹配时,或者您忽略了在模型上初始化需要初始化的属性(如列表)。基于您发布的代码行,我的猜测是模型本身是空的(可能是因为它来自数据库而您在将其发送到视图之前没有检查null),或{{1如果您的模型是实体类的实例,则属性为null,因为您忽略了初始化它,或者它没有标记为Enrollments
。
每当您从数据库中请求特定对象时,应始终检查null并正确处理。例如,如果您正在处理“详细”操作,则代码应如下所示:
virtual
如果模型上有list-style属性,则应始终通过类构造函数或自定义getter初始化它:
public ActionResult Detail(int id)
{
var foo = db.Foos.Find(id); // potentially null, if no matching id
if (foo == null)
{
return new HttpNotFoundResult();
}
return View(foo);
}
或者
public class Foo
{
public Foo()
{
Bars = new List<Bar>();
}
public List<Bar> Bars { get; set; }
}
如果你正在使用C#6,最后一个可以简化为:
public class Foo
{
private List<Bar> bars;
public List<Bar> Bars
{
get
{
if (bars == null)
{
bars = new List<Bar>();
}
return bars;
}
set { bars = value; }
}
}
最后,如果您正在处理实体框架POCO,那么这不是必需的,只要该属性为public class Foo
{
public List<Bar> Bars { get; set; } = new List<Bars>();
}
:
virtual
作为延迟加载工具的一部分,Entity Framework会自动覆盖该属性,使其永远不会为null,只有空集合才真正没有。但是,如果忽略public virtual ICollection<Bar> Bars { get; set; }
关键字,EF无法执行必要的覆盖来处理此问题。
长和短,你需要找出你希望有一个实际值的变量为null,然后进行适当的空值检查(不管这是个好主意)还是找出为什么它为null而不是您期望的价值。