Инициализаторы пользовательской коллекции
Классы, реализующие IEnumerable
и предоставляющие функцию public void Add(/* args */)
, могут быть инициализированы, как в следующем примере:
List<int> numbers = new List<int>{ 1, 2, 3 };
который вызывает функцию Add(int)
3x после инициализации List<int>
.
Есть ли способ явно определить это поведение для моих собственных классов? Например, могу ли я инициализировать вызов функции, отличной от соответствующей перегрузки Add()
?
Ответы
Ответ 1
Нет, компилятор требует использования метода Add
для инициализатора коллекции. Это определено в спецификации С# и не может быть изменено:
Спецификация языка С# - 7.5.10.3 Инициализаторы коллекции
Объект коллекции, к которому применяется инициализатор коллекции, должен иметь тип, который реализует System.Collections.IEnumerable
или возникает ошибка времени компиляции. Для каждого заданного элемента по порядку инициализатор коллекции вызывает метод Add
целевого объекта с списком выражений инициализатора элемента в виде списка аргументов, применяя нормальное разрешение перегрузки для каждого вызова. Таким образом, объект коллекции должен содержать применимый метод Add
для каждого инициализатора элемента. [акцент мой]
Конечно, метод Add
может принимать более одного аргумента (например, Dictionary<TKey, TValue>
):
dic = new Dictionary<int, int> {
{ 1, 2 },
{ 3, 4 }
};
// translated to:
dic = new Dictionary<int, int>();
dic.Add(1, 2);
dic.Add(3, 4);
Ответ 2
Добавление как пример ответа того, что работает. AFAIK, только Add будет работать. Фрагмент кода, взятый из Marius Schulz
// simple struct which represents a point in three-dimensional space
public struct Point3D
{
public readonly double X;
public readonly double Y;
public readonly double Z;
public Point3D(double x, double y, double z)
{
X = x;
Y = y;
Z = z;
}
}
// implementation of a collection of points, which respects
// the compiler convention for collection initializers and
// therefore both implements IEnumerable<T> and provides
// a public Add method
public class Points : IEnumerable<Point3D>
{
private readonly List<Point3D> _points;
public Points()
{
_points = new List<Point3D>();
}
public void Add(double x, double y, double z)
{
_points.Add(new Point3D(x, y, z));
}
public IEnumerator<Point3D> GetEnumerator()
{
return _points.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
// instantiate the Points class and fill it with values like this:
var cube = new Points
{
{ -1, -1, -1 },
{ -1, -1, 1 },
{ -1, 1, -1 },
{ -1, 1, 1 },
{ 1, -1, -1 },
{ 1, -1, 1 },
{ 1, 1, -1 },
{ 1, 1, 1 }
};