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

Aja*_*jai 22 c# nullreferenceexception

using System;
using System.Collections.Generic;

class Parent
{
   public Child Child { get; set; }
}

class Child
{
   public List<string> Strings { get; set; }
}

static class Program
{
   static void Main() {
      // bad object initialization
      var parent = new Parent() {
         Child = {
            Strings = { "hello", "world" }
         }
      };
   }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

      var parent = new Parent() {
         Child = new Child() {
            Strings = new List<string> { "hello", "world" }
         }
      };
Run Code Online (Sandbox Code Playgroud)

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

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

      var parent = new Parent() {
         Child = {
            Strings = { "hello", "world" }
         }
      };
Run Code Online (Sandbox Code Playgroud)

Jer*_*vel 18

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

var parent = new Parent();
parent.Child.Strings = new List<string> { "hello", "world" };
Run Code Online (Sandbox Code Playgroud)

其中投NullReferenceException:你想分配财产Strings由酒店载ChildChild依然null.使用构造函数首先实例化Child,处理此问题.


Guf*_*ffa 11

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

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

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

class Child {
  public List<string> Strings { get; set; }
  public Child() {
    Strings = new List<string>();
  }
}
Run Code Online (Sandbox Code Playgroud)


GSe*_*erg 6

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

它只是一种语法糖,它将花括号中的列表转换为对必须在要初始化的集合对象上定义的方法一系列调用Add()。因此,
= { "hello", "world" }的与

.Add("hello");
.Add("world");
Run Code Online (Sandbox Code Playgroud)

显然,如果未创建集合,此操作将失败并返回NullReferenceException。


小智 4

第二种语法对于只读属性有效。如果您更改代码以在各自的构造函数中初始化 Child 和 Strings 属性,则该语法有效。

class Parent
{
    public Parent()
    {
        Child = new Child();
    }

    public Child Child { get; private set; }
}

class Child
{
    public Child()
    {
        Strings = new List<string>();
    }
    public List<string> Strings { get; private set; }
}

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

    }
}
Run Code Online (Sandbox Code Playgroud)

  • 集合初始值设定项与只读属性无关。此代码之所以有效,是因为您将“Strings = new List&lt;string&gt;();”放入构造函数中,而不是因为该属性具有“私有集”。 (5认同)
  • 您的下一句话,*如果您更改代码以在各自的构造函数中初始化 Child 和 Strings 属性,则语法有效*是正确的,如果该语句后面跟着“因为对象初始化程序不创建对象”,我会投票赞成您的答案,他们只设置属性或将项目添加到集合中”,而不是“它用于只读属性”。 (2认同)