初始化没有“新列表”的列表属性会导致NullReferenceException

using System; using System.Collections.Generic; class Parent { public Child Child { get; set; } } class Child { public List Strings { get; set; } } static class Program { static void Main() { // bad object initialization var parent = new Parent() { Child = { Strings = { "hello", "world" } } }; } } 

上面的程序编译很好,但在运行时崩溃, Object引用未设置为对象的实例

如果您在上面的代码段中注意到,我在初始化子属性时省略了new

显然,正确的初始化方法是:

  var parent = new Parent() { Child = new Child() { Strings = new List { "hello", "world" } } }; 

我的问题是为什么C#编译器在看到第一个构造时不会抱怨?

为什么破坏的初始化有效语法?

  var parent = new Parent() { Child = { Strings = { "hello", "world" } } }; 

第二种语法对readonly属性有效。 如果更改代码以初始化相应构造函数中的Child和Strings属性,则语法有效。

 class Parent { public Parent() { Child = new Child(); } public Child Child { get; private set; } } class Child { public Child() { Strings = new List(); } public List Strings { get; private set; } } static class Program { static void Main() { // works fine now var parent = new Parent { Child = { Strings = { "hello", "world" } } }; } } 

它没有破坏语法,是你在一个根本没有实例化的属性上使用对象初始化器。 你写的内容可以扩展到

 var parent = new Parent(); parent.Child.Strings = new List { "hello", "world" }; 

抛出NullReferenceException :您正在尝试分配属性Child包含的属性,而Child仍为null 。 使用构造函数首先实例化Child ,处理此问题。

初始化没有任何问题,但它正在尝试初始化不存在的对象。

如果类具有创建对象的构造函数,则初始化有效:

 class Parent { public Child Child { get; set; } public Parent() { Child = new Child(); } } class Child { public List Strings { get; set; } public Child() { Strings = new List(); } } 

您似乎误解了集合初始化程序的function。

它只是一个语法糖,它将大括号中的列表转换为一系列对Add()方法的调用,该方法必须在正在初始化的集合对象上定义。
因此,你的= { "hello", "world" }具有相同的效果

 .Add("hello"); .Add("world"); 

显然,如果未创建集合,则会因NullReferenceException而失败。

始终在编译时检查引用null。 虽然编译器有时会在分配变量之前警告使用变量。 编译器正常工作。 这是一个运行时错误。