В Visual Studio 2015 отсутствует новое ключевое слово - ошибка компилятора

Я работал над одним из наших новых приложений, когда совершил глупую ошибку… Я забыл написать: "new ClassName" внутри инициализатора объекта. Странно, VS просто скомпилировал код... без каких-либо ошибок или предупреждений. (Я использовал VS 2015, .Net 4.5.2)

Мой код:

var target = new MyClass
{
    MyValues = new List<MyOtherClass>
    {
        new MyOtherClass
        {
            Start = new DateTimeValue
            {
                DateTime = new DateTime(2015, 08, 23)
            },
            End = {
                DateTime = new DateTime(2015, 08, 23)
            }
        }
    }
};

(Start и End имеют тип DateTimeValue)

Когда я запускаю приложение, этот код вызывает исключение NullReferenceException. (Добавление "нового DateTimeValue" решило проблему). Почему не было ошибки от компилятора?

2 ответа

Решение

Там нет ничего плохого там вообще. Он использует инициализатор объекта для End который устанавливает свойства, используя существующее значение вместо назначения нового значения End, Ваш код эквивалентен:

var tmp0 = new MyClass();
var tmp1 = new List<MyOtherClass>();
var tmp2 = new MyOtherClass();
var tmp3 = new DateTimeValue();
tmp3.DateTime = new DateTime(2015, 8, 23);
// Note the assignment to Start here
tmp2.Start = tmp3;

// No assignment to End -
// it's calling the End "getter" and then the DateTime "setter" on the result
tmp2.End.DateTime = new DateTime(2015, 8, 23);
tmp1.Add(tmp2);
tmp0.MyValues = tmp1;
var target = tmp0;

Из спецификации C# 5, раздел 7.6.10.2:

Инициализатор члена, который указывает инициализатор объекта после знака равенства, является инициализатором вложенного объекта, то есть инициализацией внедренного объекта. Вместо назначения нового значения полю или свойству, назначения в инициализаторе вложенного объекта обрабатываются как присвоения членам поля или свойства.

Это именно то, что вы делаете здесь - { DateTime = ... } часть является инициализатором объекта.

Потому что это правильный синтаксис.

Это примерно означает следующее:

var target = new MyClass();
target.MyValues = new List<MyOtherClass>();

var i = new MyOtherClass();

i.Start = new DateTimeValue();
i.Start.DateTime = new DateTime(2015, 08, 23);

i.End.DateTime = new DateTime(2015, 08, 23);

target.MyValues.Add(i);

За исключением того, что свойства устанавливаются только один раз и никогда не читаются компилятором. Это потребовало бы использования дополнительных временных переменных (как Джон сделал в своем ответе), но я не стал писать их здесь для простоты.

Этот синтаксис полезен для случая, когда MyOtherClass создает экземпляр End Свойство в своем конструкторе. Его также можно использовать, когда свойство доступно только для чтения.

Другие вопросы по тегам