#c# #object-initializers #collection-initializer
#c# #инициализаторы объектов #коллекция-инициализатор
Вопрос:
Я заметил странное поведение при инициализации свойства коллекции.
Рассмотрим:
class X
{
public IList<int> Ints { get; set; }
}
Я могу инициализировать Ints
так:
var theObject = new X
{
Ints = { 12, 3, 4, 5, 6 }
};
Но я не могу этого сделать:
var x = new X();
x.Ints = { 12, 3, 4, 5, 6 }
Есть идеи, почему? Это кажется довольно неинтуитивным.
Комментарии:
1. «потому что так сказано в спецификации языка»
2. @Sweeper Спасибо, но это похоже на ответ на все. Что-то более конкретное было бы более полезным 🙂
3. Подробности об этом синтаксическом сахаре см. В разделе Инициализаторы объектов и коллекций .
4. Хотите, чтобы я указал вам, где именно в спецификации это сказано?
5. Я бы хотел это увидеть 🙂
Ответ №1:
new X ...
является началом выражения создания объекта. В такого рода выражениях разрешен инициализатор объекта или коллекции:
object_creation_expression
: 'new' type '(' argument_list? ')' object_or_collection_initializer?
| 'new' type object_or_collection_initializer // <--- here!
;
object_or_collection_initializer
: object_initializer
| collection_initializer
;
В вашем коде у вас есть инициализатор объекта { Ints = ... }
. Внутри этого есть другой инициализатор коллекции { 12, 3, 4, 5, 6 }
. Это разрешено в соответствии с грамматикой:
object_initializer
: '{' member_initializer_list? '}'
| '{' member_initializer_list ',' '}'
;
member_initializer_list
: member_initializer (',' member_initializer)*
;
member_initializer
: initializer_target '=' initializer_value
;
initializer_target
: identifier
| '[' argument_list ']'
;
initializer_value
: expression
| object_or_collection_initializer // <---- here!
;
An initializer_value
может быть либо выражением, либо другим object_or_collection_initializer
. Это также подразумевает, что, хотя они могут выглядеть так, object_or_collection_initializer
, т. Е. Такие вещи, как { 12, 3, 4, 5, 6 }
, не являются своего рода выражением.
С другой стороны, назначения не позволяют этого. Присваивания позволяют выражению находиться только с правой стороны:
assignment
: unary_expression assignment_operator expression
;
Ответ №2:
Как указано в комментариях, это пример инициализатора коллекции.
Это действительно синтаксический сахар для чего-то вроде следующего:
var theObject = new X();
theObject.Items.Add(12);
theObject.Items.Add(3);
theObject.Items.Add(4);
theObject.Items.Add(5);
theObject.Items.Add(6);
Таким образом можно инициализировать все, что соответствует правильной «форме». (По сути, он ищет Add(...)
метод, соответствующий правильной сигнатуре ваших типов.) Вы даже можете использовать это для инициализации коллекций словарей.