Пользовательские Инициализаторы Коллекции - PullRequest
47 голосов
/ 23 марта 2010

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

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

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

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

Ответы [ 2 ]

65 голосов
/ 23 марта 2010

Нет, компилятору требуется метод с именем 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);
4 голосов
/ 26 ноября 2015

Добавление в качестве примера ответа о том, что работает. 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 }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...