Подтвердить что ты не робот

Инициализаторы пользовательской коллекции

Классы, реализующие IEnumerable и предоставляющие функцию public void Add(/* args */), могут быть инициализированы, как в следующем примере:

List<int> numbers = new List<int>{ 1, 2, 3 };

который вызывает функцию Add(int) 3x после инициализации List<int>.

Есть ли способ явно определить это поведение для моих собственных классов? Например, могу ли я инициализировать вызов функции, отличной от соответствующей перегрузки Add()?

4b9b3361

Ответ 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 }
};