Пользовательские инициализаторы коллекции
Классы, которые реализуют IEnumerable
и предоставить public void Add(/* args */)
Функция может быть инициализирована как в следующем примере:
List<int> numbers = new List<int>{ 1, 2, 3 };
который вызывает Add(int)
функция 3x после инициализации List<int>
,
Есть ли способ определить это поведение явно для моих собственных классов? Например, я мог бы инициализатор вызвать функцию, отличную от соответствующей Add()
перегрузка?
2 ответа
Нет, компилятору требуется метод с именем Add
для работы инициализатора коллекции. Это определено в спецификации C# и не может быть изменено:
Спецификация языка C# - 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);
Добавление просто в качестве примера ответа о том, что работает. AFAIK, только добавить будет работать. Фрагмент кода, взятый у Мариуса Шульца
// 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 }
};