Пользовательские инициализаторы коллекции

Классы, которые реализуют 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 }
};
Другие вопросы по тегам