MVC3控制器中的NullReferenceException

时间:2011-09-10 19:32:56

标签: c# asp.net-mvc-3

我正在玩MVC3,尝试创建小型测试项目,模拟我预计将在我从PHP迁移的大型项目中遇到的问题。我在使用以下元素在项目中实例化“model”变量时不断得到“NullReferenceException”:

型号:

public class MainModel
{
    public IEnumerable<Chemical> chemicals { get; set; }

}

public class Chemical
{
    public int ChemicalId { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Hazard> Hazards { get; set; }

}

public class Hazard
{
    public int HazardId { get; set; }
    public string Description { get; set; }

    public virtual ICollection<Chemical> Chemicals { get; set; }
}

控制器:

public class MainController : Controller
{

    public ActionResult Index()
    {

        var h1 = new Hazard { HazardId = 1, Description = "Flammable" };
        var h2 = new Hazard { HazardId = 2, Description = "Carcinogen" };
        var h3 = new Hazard { HazardId = 3, Description = "Water Reactive" };

        var model = new [] {
            new Chemical { ChemicalId = 1, Name = "Benzene", Hazards = {h1, h2}},
            new Chemical { ChemicalId = 2, Name = "Sodium", Hazards = { h3 } },
            new Chemical { ChemicalId = 3, Name = "Chloroform", Hazards =  { h2 } },
            new Chemical { ChemicalId = 4, Name = "Water" }
        }; //NULL EXCEPTION THROWN HERE

        return View(model);
    }

}

所以,我有两个问题:

  1. 为什么我一直得到NullReferenceException,怎么能修复它?
  2. 在编写此代码时,我使用此StackOverFlow Page作为起点。为什么这样可以,但我写的不是?当然,我没有测试这段代码,但作者似乎非常称职。
  3. 谢谢!

3 个答案:

答案 0 :(得分:2)

实际问题与MVC无关。您正在使用匿名对象实例化ICollection Hazards,我相信编译器无法正确解析此代码,因此它在运行时失败。这是快速修复:

var model = new [] {
    new Chemical { ChemicalId = 1, Name = "Benzene", Hazards = new List<Hazard>{h1, h2}},
    new Chemical { ChemicalId = 2, Name = "Sodium", Hazards = new List<Hazard>{ h3 } },
    new Chemical { ChemicalId = 3, Name = "Chloroform", Hazards =  new List<Hazard>{ h2 } },
    new Chemical { ChemicalId = 4, Name = "Water" }
};

请注意List<Hazards>{h1, h2}的使用,而不仅仅是{h1, h2}

答案 1 :(得分:1)

  

为什么我一直得到NullReferenceException,它怎么可能   固定?

ICollection属性Hazards最初为空 - 在创建模型时必须使用构造函数:

var model = new[] {
    new Chemical { ChemicalId = 1, Name = "Benzene", Hazards = new List<Hazard>() {h1, h2}},
    new Chemical { ChemicalId = 2, Name = "Sodium", Hazards = new List<Hazard>(){ h3 } },
    new Chemical { ChemicalId = 3, Name = "Chloroform", Hazards =  new List<Hazard>(){ h2 } },
    new Chemical { ChemicalId = 4, Name = "Water" }
};

您目前拥有的代码将尝试添加,即{h1,h2}Hazards - 这是null并抛出NullReferenceException。另一种方法是在Hazards构造函数中创建一个新的空Chemical集合 - 然后您可以保持当前代码不变:

public class Chemical
{
    public Chemical()
    {
        _hazards = new List<Hazard>();
    }
    //..
}

答案 2 :(得分:1)

由于您来自PHP,或许对您概述CSharp的语法快捷方式会更有帮助!
乍一看它们真的很混乱,因为语法很相似。但是在快速介绍之后,你会学会爱他们。

集合初始值设定项

Collection Initializer将项添加到集合中。语法为new SOMECOLLECTION { value, value, value }

填充集合的传统方法:

var items = new List<int>();
items.Add(1);
items.Add(2);
items.Add(3);

Collection Initializer 方式 - 这将编译为几乎完全相同的代码:

var items = new List<int>(){ 1, 2, 3 };

旁注:数组与列表 - 我会说List更常用,因为它的大小可以改变。但这主要是个人偏好。创建数组的简便方法是:var items = new int[]{ 1, 2, 3 };,但您也可以省略类型,编译器会解决它(也就是隐式类型数组):var items = new []{ 1, 2, 3 };

对象初始值设定项

Object Initializer设置新对象的属性。语法为new SOMEOBJECT { Property = value, Property = value }

填充对象属性的传统方法:

var item = new Item();
item.First = "Chuck";
item.Last = "Norris";

对象初始化程序方式:

var item = new Item(){ First = "Chuck", Last = "Norris" };

匿名对象

我只是提到这一点,因为匿名对象的语法与其他对象非常相似,但是做了很多不同的事情。如果你不了解它们,它们会非常混乱!

语法看起来像Collection和Object Initializers的组合:new { AnyPropertyName = value, anyVariableNameBecomesAProperty, someOtherObject.SomeProperty }

让我解释一下!编译器将创建一个“匿名对象”,它具有3个属性AnyPropertyNameanyVariableNameBecomesAPropertySomeProperty,并以与Object Initializer相同的方式初始化值。如果未指定属性名称,则从源中推断出名称。

我希望这可以帮助您理解为什么new { h1, h2 }(新匿名对象)与new []{ h1, h2 }(新数组)不同。