Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
411 views
in Technique[技术] by (71.8m points)

c# - NullReferenceException with object initializer suggested by resharper

I have a strange issue with the object initializer syntax.

Here are my sample classes:

public class Foo
{
    public Bah BahProp { get; set; }
}

public class Bah
{
    public int Id { get; set; }
}

Consider following three ways to initialize an object:

The old, verbose but explicit way, working correctly:

var foo1 = new Foo();
foo1.BahProp = new Bah();
foo1.BahProp.Id = 1;
// correctly initialized

The second way i'm always using, using object initializer syntax:

var foo2 = new Foo
{
    BahProp = new Bah { Id = 1 }
}; // correctly initialized

A third way resharper has suggested my collegue with a different resharper version(is it a bug?):

var foo3 = new Foo
{
    BahProp = { Id = 1 }
};  // NullReferenceException

What is the last approach doing differently?

My resharper version is 2016.1.1, my colleague was on 10.02. My resharper suggested the second way. But what does the third way do and when is it useful?

Update: So it seems that it was a bad resharper sugestion to use the last way, that's why they have changed it meanwhile to use the second way.

You can avoid the NullReferenceException if you want to use the third way by initializing all properties/fields that are reference types inline or in the constructor.

I will definitely not use this strange property assignment syntax.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
new Foo { BahProp = { Id = 1 } }

compiles to:

new Foo().BahProp.Id = 1;

or, little more verbose:

var foo3 = new Foo();
foo3.BahProp.Id = 1;

So BahProp is null. You're not constructing it.
(This is perhaps the most confusing syntax in all of C#)
Option 2 works because you're calling the constructor of Bah.

Option 3 would also work if you initialize BahProp inside the constructor of Foo. It will have been constructed by the time BahProp = { Id = 1 } is called.

The same is seen with collection initializers:

public class Foo {
    public List<int> Numbers { get; set; }
}

var foo = new Foo { Numbers = { 1, 2, 3 } };

This does not initialize the List. It only calls Add on it.

You really must see new MyObject() { X = 1, Y = 2 } as two distinct parts:
new MyObject() constructs a new object and
{ X = 1, Y = 2 } sets the values of its properties (and that's all it does).
Object and collection initializers can be nested. The top-level initializer must follow a constructor, but a nested initializer does not.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...