Простой способ реализовать коллекцию? - PullRequest
2 голосов
/ 26 мая 2011

Я занимаюсь разработкой класса коллекции, который должен реализовывать IEnumerator и IEnumerable.

В моем первом подходе я реализовал их напрямую.Теперь я обнаружил ключевое слово yield и смог полностью упростить замену интерфейсов IEnumerator / IEnumerable на свойство «только для чтения», которое использует yield для возврата IEnumerable в цикле.

Мой вопрос:Можно ли использовать yield таким образом, чтобы я мог выполнять итерации по самому классу, не реализуя IEnumerable / IEnumerator?

Т.е. я хочу иметь функциональность, аналогичную наборам каркасов:

List<int> myList = new List<int>();
foreach (int i in myList)
{
    ...
}

Возможно ли это вообще?

Обновление: Похоже, мой вопрос был плохо сформулирован.Я не против реализации IEnumerator или IEnumerable;Я просто подумал, что единственный способ сделать это - использовать старые методы Current / MoveNext / Reset.

Ответы [ 2 ]

9 голосов
/ 26 мая 2011

У вас не будет для реализации IEnumerable<T> или IEnumerable, чтобы заставить foreach работать - но было бы неплохо сделать это.Это очень легко сделать:

public class Foo : IEnumerable<Bar>
{
    public IEnumerator<Bar> GetEnumerator()
    {
        // Use yield return here, or 
        // just return Values.GetEnumerator()
    }

    // Explicit interface implementation for non-generic
    // interface; delegates to generic implementation.
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

Альтернатива, которую не реализует IEnumerable<T>, просто вызовет ваше свойство Values, но при этом предоставит метод GetEnumerator():

public class Foo
{
    public IEnumerator<Bar> GetEnumerator()
    {
        // Use yield return here, or 
        // just return Values.GetEnumerator()
    }
]

Хотя это будет работать, это означает, что вы не сможете передать свою коллекцию чему-либо, ожидающему IEnumerable<T>, например LINQ to Objects.

Это малоизвестныйтот факт, что foreach будет работать с любым типом, поддерживающим метод GetEnumerator(), который возвращает тип с соответствующими MoveNext() и Current членами.Это было сделано для того, чтобы разрешить строго типизированные коллекции перед генериками, где итерация по коллекции не будет блокировать типы значений и т. Д. Сейчас это действительно не нужно, IMO.

1 голос
/ 26 мая 2011

Ты мог бы сделать что-то подобное, но почему? IEnumerator уже просто.

Interface MyEnumerator<T>
{
    public T GetNext();
}

public static class MyEnumeratorExtender
{
    public static void MyForeach<T>(this MyEnumerator<T> enumerator,
        Action<T> action)
    {
        T item = enumerator.GetNext();
        while (item != null)
        {
            action.Invoke(item);
            item = enumerator.GetNext();
        }
    }
}

Я бы предпочел ключевое слово in и не хотел бы переписывать linq.

...