Объединение инициализатора списка и инициализатора объекта - PullRequest
15 голосов
/ 06 июня 2011

Можно ли объединить инициализатор списка и инициализатор объекта одновременно? Учитывая следующее определение класса:

class MyList : List<int>
{
    public string Text { get; set; }
}

// we can do this
var obj1 = new MyList() { Text="Hello" };

// we can also do that
var obj2 = new MyList() { 1, 2, 3 };

// but this one doesn't compile
//var obj3 = new MyList() { Text="Hello", 1, 2, 3 };

Это специально или это ошибка или отсутствующая функция компилятора c #?

Ответы [ 3 ]

26 голосов
/ 06 июня 2011

Нет, если смотреть на определения из раздела 7.6.10 спецификации C #, выражение object-or-collection-initializer равно или , object-initializer или a collection-initializer.

object-initializer состоит из нескольких member-initializer с, каждый из которых имеет форму initializer = initializer-value, тогда как collection-initializer состоит из нескольких element-initializer с, каждый из которых является non-assigment-expression.

Так что, похоже, это сделано специально - возможно, ради простоты.Я не могу сказать, что когда-либо хотел сделать это, если честно.(Я обычно не получал бы от List<int> для начала - я бы сочинил его вместо этого.) Мне бы очень не хотелось видеть:

var obj3 = new MyList { 1, 2, Text = "Hello", 3, 4 };

РЕДАКТИРОВАТЬ: Если вы действительно, действительно Если вы хотите включить это, вы можете поместить это в класс:

class MyList : List<int>
{
    public string Text { get; set; }
    public MyList Values { get { return this; } }
}

, и в этот момент вы можете написать:

var obj3 = new MyList { Text = "Hello", Values = { 1, 2, 3, 4 } };
3 голосов
/ 06 июня 2011

Нет, это не ошибка. Это дизайн языка.

Когда вы пишете

var obj1 = new MyList() { Text="Hello" };

это эффективно переведено компилятором в

MyList temp = new MyList();
temp.Text = "Hello";
MyList obj = temp;

Когда вы пишете

var obj2 = new MyList() { 1, 2, 3 };

это эффективно переведено компилятором в

MyList temp = new MyList();
temp.Add(1);
temp.Add(2);
temp.Add(3);
MyList obj2 = temp;

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

Кроме того, вы не должны наследовать от List<T>. См .: Наследование списка Реализация коллекций - плохая идея?

2 голосов
/ 06 июня 2011

Если вы хотите получить что-то подобное этой функциональности, рассмотрите возможность создания аргумента конструктора:

var x = new CustomList("Hello World") { 1, 2, 3 }
...