Синтаксис инициализатора

Мне нравится C# 3 синтаксис инициализатора и часто его использую, но сегодня при просмотре в Reflector обнаружилось следующее:

var binding = new WSHttpBinding
{
  ReaderQuotas = { MaxArrayLength = 100000 },
  MaxReceivedMessageSize = 10485760
};

Сначала я подумал, что это ошибка, но он компилируется! Думаю, я все еще узнаю что-то новое все время. :)

Насколько я могу судить, он устанавливает свойство MaxArrayLength свойства ReaderQuotas свойства WSHttpBinding.

Этот синтаксис создает новый объект ReaderQuotas, а затем устанавливает свойство, или он предполагает, что свойство уже инициализировано? Является ли это общим способом инициализации «дочерних» свойств?

Я нахожу синтаксис немного запутанным...


person leppie    schedule 07.01.2010    source источник
comment
Вас может заинтересовать этот пост, в котором обсуждается семантика и варианты использования для этого типа инициализатора   -  person ChaseMedallion    schedule 15.10.2014


Ответы (2)


Нет, это не создает новые объекты, если вы не используете = new SomeType {...}:

var binding = new WSHttpBinding
{
    ReaderQuotas = new XmlDictionaryReaderQuotas { MaxArrayLength = 100000 },
    MaxReceivedMessageSize = 10485760
};

В вашем примере показан синтаксис инициализатора для установки свойств существующих подобъектов. Существует также аналогичный синтаксис для вызова методов «Добавить» для коллекций.

Ваш код в целом сопоставим с:

var binding = new WSHttpBinding();
binding.ReaderQuotas.MaxArrayLength = 100000;
binding.MaxReceivedMessageSize = 10485760;
person Marc Gravell    schedule 07.01.2010
comment
Выглядит идентично этому, есть ли что-то большее, чем просто синтаксическая разница? Похоже (если только ReaderQuotas не инициализирован в конструкторе WSHttpBinding), он должен генерировать исключение - person James; 07.01.2010
comment
Спасибо, это просто застало меня врасплох :) Я предполагаю, что под «Добавить» вы имеете в виду инициализатор коллекции? - person leppie; 07.01.2010
comment
@james: в этом случае я бы ожидал исключения, но отсутствие исходного кода может привести к путанице, если вы не знаете, что делается в конструкторе. Некоторые перегрузки конструктора могут инициализировать или не инициализировать это свойство, что приведет к еще большей путанице. - person leppie; 07.01.2010
comment
Не стоит отдельного дополнительного ответа, но это обсуждается в главе 8 C# in Depth. Первая редакция этой главы доступна бесплатно на сайте manning.com/skeet. - person Jon Skeet; 07.01.2010
comment
Джеймс, разница тонкая. Хотя код семантически эквивалентен этому, на самом деле мы генерируем temp = new Binding(); бла бла бла; привязка var = temp; Почему? Потому что привязка переменной не должна использоваться внутри ее собственного инициализатора! Это скорее проблема курицы и яйца. Если бы мы сгенерировали код точно так, как предлагает Марк, то связывание было бы инициализировано до того, как запустится код инициализатора, и кто-то потенциально мог бы наблюдать связывание в его частично инициализированном состоянии. - person Eric Lippert; 07.01.2010
comment
Я могу ошибаться, но IIRC также немного отличается, если в назначении есть несколько свойств, поскольку в синтаксисе инициализатора член оценивается только один раз, поэтому ..., SomeProp = { Foo = 1, Bar = 2 } будет var tmp = obj.SomeProp; tmp.Foo = 1; tmp.Bar = 2;, а не obj.SomeProp.Foo = 1; obj.SomeProp.Bar = 2;. - person Marc Gravell; 07.01.2010

Это немного запутанно, согласен.

Вы должны прочитать раздел 7.6.10.2 спецификации; там все объясняется. Например:

Инициализатор члена, указывающий выражение после знака равенства, обрабатывается так же, как присваивание полю или свойству.

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

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

person Eric Lippert    schedule 07.01.2010