Initializing list property without “new List” causes NullReferenceException

邮差的信 提交于 2019-11-26 14:48:22

问题


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" }
         }
      };
   }
}

The above program compiles fine, but crashes at runtime with Object reference not set to an instance of the object.

If you notice in the above snippet, I have omitted new while initializing the child properties.

Obviously the correct way to initialize is:

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

My question is why does the C# compiler not complain when it sees the first construct?

Why is the broken initialization valid syntax?

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

回答1:


The second syntax is valid for readonly properties. If you change the code to initialise the Child and Strings properties in the respective constructors, the syntax works.

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" }
            }
        };

    }
}



回答2:


It's not broken syntax, it's you who uses an object initializer on a property that's simply not instantiated. What you wrote can be expanded to

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

Which throws the NullReferenceException: you're trying to assign the property Strings contained by the property Child while Child is still null. Using a constructor to instantiate Child first, takes care of this.




回答3:


There is nothing wrong with the initialisation, but it's trying to initialise objects that doesn't exist.

If the classes have constructors that create the objects, the initialisation works:

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>();
  }
}



回答4:


You seem to misunderstand what the collection initializer does.

It is a mere syntactic sugar that converts the list in the braces into a series of calls to Add() method that must be defined on the collection object being initialized.
Your = { "hello", "world" } is therefore has the same effect as

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

Obviously this will fail with a NullReferenceException if the collection is not created.




回答5:


Referencing a null can`t always be checked for at compile time. Although the compiler sometimes warns of using a variable before it has been assigned. The compiler works correctly. This is a run-time error.



来源:https://stackoverflow.com/questions/32342188/initializing-list-property-without-new-list-causes-nullreferenceexception

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!