18

The following testcase throws a null-reference exception, when it tries to assign Id to an object which is null, since the code is missing the "new R" before the object initializer.

Why is this not caught by the compiler? Why is it allowed, in which use-cases would this be a meaningful construct?

[TestClass]
public class ThrowAway
{
    public class H
    {
        public int Id { get; set; }
    }

    public class R
    {
        public H Header { get; set; }
    }

    [TestMethod]
    public void ThrowsException()
    {
        var request = new R
                      {
                          Header =
                          {
                              Id = 1
                          },
                      };
    }
}
5
  • You have to initialize the Header property of your R object. var request = new R { Header = new H { Id = 1 } }; Commented Jun 3, 2015 at 13:00
  • 3
    Very interesting question... it isn't even clear if the compiler is doing a cast or what... Commented Jun 3, 2015 at 13:04
  • 3
    Very interesting question, but extremely poor title in my opinion. Would you consider changing it to the actual question you are asking? Commented Jun 3, 2015 at 13:13
  • I'd be happy to change it, what did you have in mind? Commented Jun 3, 2015 at 13:29
  • That's a lot better I think (you missed the question mark at the end :P ). Upvoted now. Commented Jun 3, 2015 at 13:52

1 Answer 1

19

The compiler doesn't give a warning because you could have:

public class R
{
    public H Header { get; set; }

    public R()
    {
        Header = new H();
    }
}

so Header could be initialized by someone/something. Solving if someone/something will initialize Header is a complex problem (probably similar to the Halting problem)... Not something that a compiler wants to solve for you :-)

From the C# specifications:

A member initializer that specifies an object initializer after the equals sign is a nested object initializer, i.e. an initialization of an embedded object. Instead of assigning a new value to the field or property, the assignments in the nested object initializer are treated as assignments to members of the field or property. Nested object initializers cannot be applied to properties with a value type, or to read-only fields with a value type.

We are in the case of nested initializer, and see the bolded part. I didn't know it.

Now, note that new R { } is, by C# spec, an 7.6.10.1 Object creation expressions followed by an object-initializer, while the Header = { } is a "pure" 7.6.10.2 Object initializers.

Sign up to request clarification or add additional context in comments.

5 Comments

Same question as to the another post here - why did it allow Header = {Id = 1}? This looks plain wrong anyway, doesn't it?
@Andrei At least I explained the Why is this not caught by the compiler? :-)
Sorry, I still don't get it. Not trying to argue, just very curious myself. Compiler should have failed on such syntax, no matter if there is initialization in ctor, right?
@Andrei Found the part of C# spec that defines this case. My response was more in the tone of "why isn't there a warning" (and in fact my response starts with a The compiler doesn't give a warning because you could have:)
Thanks xanatos, I think I can see why it can't warn or fail now. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.