0

Why does the following code compile, but throw a NullReferenceException?

using System.Collections.Generic;

class Program
{
    static void Main()
    {
        C c = new C { P = { "" } };
    }
}

class C
{
    public List<string> P;
}
Jeno Csupor
  • 2,869
  • 6
  • 30
  • 35
  • 1
    Because `P` in `C` is null and your trying to assign to it `P = { "" }` – Liam Oct 20 '16 at 13:14
  • 1
    Because the state of P is not known until runtime. You could have code that instanciates the object or not. From a compiler point of view it checks the object is correct, not wether it exists. The compiler can't traverse every logic tree in your entire code base – Liam Oct 20 '16 at 13:16
  • @juharr How could the compiler know (in the general case) whether `C`'s constructor sets `P` to anything? –  Oct 20 '16 at 13:16
  • @juharr Sure, because it's special syntax that only works for initialisation. –  Oct 20 '16 at 13:18
  • Lists cannot be assigned like that, they need to be initialized first – downrep_nation Oct 20 '16 at 13:20
  • 2
    It's because the `P = { "" }` part is being translated into `P.Add("")`. – juharr Oct 20 '16 at 13:20
  • 4
    C#'s syntax is misleading here. `=` usually means assignment or replacement, but actually it's used as append. – qxg Oct 20 '16 at 13:24
  • did any of the given answers help you solving your problem? – fubo Oct 21 '16 at 12:13

2 Answers2

1

Basically the code

C c = new C { P = { "" } };

is really short hand for

C temp = new C();
temp.P.Add("");
C c = temp;

So it's not creating the list, just trying to add to it and thus the run time error, but no compilation error.

juharr
  • 31,741
  • 4
  • 58
  • 93
  • using System; using System.Collections.Generic; public class Program { public static void Main(string[] args) { C c = new C { P = { "b" } }; Console.WriteLine(c.P.Count); } } class C { public List P { get; private set; } public C() { P = new List { "a" }; } } – Jeno Csupor Oct 22 '16 at 10:45
  • The syntactic sugar is too confusing here, in my opinion. If you write `C c = new C { P = new List { "" } };` everything is good because now the last `=` means assign to `P` (___write___) which is certainly OK. In the original example `=` means ___read___ the value of `P` and attempt to invoke the `Add` method that exists on the compile-time type of `P`. – Jeppe Stig Nielsen Oct 22 '16 at 11:38
  • @CsuporJenő The question was about why it compiles, but causes an exception, not how to fix it to make it not cause an exception. – juharr Oct 24 '16 at 11:36
  • @JeppeStigNielsen I agree that it's confusing, but without it we'd be left to do a bunch of `Add` calls or maybe a `AddRange` if available if the property is read only. – juharr Oct 24 '16 at 11:39
0

The reason it complies is because

C c = new C { P = { "" } };

is valid C#.

It only checks to see if P is not null at run-time - hence the runtime NullReferenceException.

ChrisF
  • 134,786
  • 31
  • 255
  • 325
  • 2
    Seriously, re-opening and answering obvious duplicates? –  Oct 20 '16 at 13:21
  • 2
    @hvd - I didn't think it was an obvious duplicate. However, I see I have been overruled. Unfortunately I didn't see the runtime reference buried in the many answers to that question. – ChrisF Oct 20 '16 at 13:28
  • I'd say it's covered by the `Book b1 = new Book { Author = { Age = 45 } };` part of the answer there, under the "Indirect" heading. If you can explain why you feel it's not covered by that, I'd be more than happy to attempt to edit that other answer to make it clearer. I do hope you at least agree it *should* be answered by the canonical question & answer. That's why we have them. –  Oct 20 '16 at 13:33
  • @hvd maybe we need to have separate answers on the canonical question and the ability to specify an **answer** when closing as a duplicate so that the link goes directly to the answer for this case, rather than making everyone trawl through dozens of answers for this exact case. – ChrisF Oct 20 '16 at 13:39