Несколько перечислителей для IEnumerable - PullRequest
2 голосов
/ 25 августа 2010

У меня есть пользовательская коллекция, в которой есть много режимов генерации объектов.
Она может генерировать все, по одному объекту за раз или за N объектов одновременно.
Я бы хотела иметь опциюпереключаться между реализациями генерации во время выполнения и даже, возможно, создавать новые.
Я ищу что-то с таким синтаксисом:

foreach(var obj in myCollection.EnumerateAs(new LazyEnumerator())
{
   // ...
}

Мои проблемы:
Я незнаете, что возвращает EnumerateAs()?Я предполагаю, что это IEnumerator, но будет ли он по-прежнему перечислителем моего списка?
LazyEnumerator наследует от IEnumerator?
Как он узнает о myCollection?

Ответы [ 3 ]

5 голосов
/ 25 августа 2010

Возвращаемое значение вашего EnumerateAs() должно быть IEnumerable<T>, где T - это тип объекта, который содержится в вашей коллекции.Я рекомендую прочитать больше о yield return , так как это может помочь вам понять, как работает перечисление.Класса по умолчанию для предоставления перечисления «стратегия» не существует, но вы можете легко реализовать нечто подобное, используя возвращаемый доход для базовой коллекции различными способами.

Из вашего вопроса точно не ясно, как стратегии перечислениябудет взаимодействовать с вашим классом коллекции.Похоже, что вы можете искать что-то вроде:

public interface IEnumerationStrategy<TCollection, T>
{
    IEnumerable<T> Enumerate(TCollection source);
}

public class Quark {}

public class MyCollection
{
    public IEnumerable<Quark> EnumerateAs(IEnumerationStrategy<MyCollection, Quark> strategy)
    {
        return strategy.Enumerate(this);
    }

    //Various special methods needed to implement stategies go here
}

public class SpecialStrategy : IEnumerationStrategy<MyCollection, Quark>
{
    public IEnumerable<Quark> Enumerate(MyCollection source)
    {
        //Use special methods to do custom enumeration via yield return that depends on specifics of MyCollection
    }
}

Обратите внимание, что вы также можете заменить класс стратегии на простую стратегию Func<MyCollection, IEnumerable<T>>, но приведенный выше наиболее точно соответствует желаемому синтаксису.

0 голосов
/ 14 июня 2012
public class AltEnumerator : System.Collections.IEnumerable
{

    private System.Collections.IEnumerator _base;

    public AltEnumerator(System.Collections.IEnumerator _pbase)
    {
        _base = _pbase;
    }


    #region IEnumerable Members

    public System.Collections.IEnumerator GetEnumerator()
    {
        return _base ;
    }

    #endregion
}

в вашем классе вы можете:

    public AltEnumerator Iterate(IterDIrection How )
    {
        switch (How)
        {
            case TwoDimArray<T>.IterDIrection.RghtLeftTopBottom:
                return new AltEnumerator(GetRightLeft());
        }
        return new AltEnumerator(GetEnumerator());
    }

    private System.Collections.IEnumerator GetRightLeft()
    {
        for (int cndx = PutSlotArray.GetLength(1) - 1; cndx >= 0; cndx--)
            for (int rndx = 0; rndx < PutSlotArray.GetLength(0); rndx++)
                if (PutSlotArray[rndx, cndx] != null)
                    yield return PutSlotArray[rndx, cndx];
    }

    #region IEnumerable Members

    public System.Collections.IEnumerator GetEnumerator()
    {
        foreach (T ps in PutSlotArray)
            if (ps != null)
                yield return ps;
    }

    #endregion

очень гибко.

0 голосов
/ 03 апреля 2011

Я бы посоветовал вам начать с создания функций GetEnumeratorInFirstStyle, GetEnumeratorInSecondStyle и т. Д. (Конечно же, использовать имена, подходящие для вашего приложения), а затем создать новые структуры, например (например, в синтаксисе vb, но их легко можно преобразовать в C #):

Class enumTest
    Function GetEnumeratorInFirstStyle() As IEnumerator(Of Integer)
        Return Enumerable.Empty(Of Integer)() ' Real code would do something better
    End Function
    Private Structure FirstStyleEnumerable
        Implements IEnumerable(Of Integer)

        Private myEnumTest As enumTest

        Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of Integer) Implements System.Collections.Generic.IEnumerable(Of Integer).GetEnumerator
            Return myEnumTest.GetEnumeratorInFirstStyle
        End Function

        Public Function GetEnumerator1() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
            Return myEnumTest.GetEnumeratorInFirstStyle
        End Function

        Sub New(ByVal newEnumTest As enumTest)
            myEnumTest = newEnumTest
        End Sub
    End Structure
    Public ReadOnly Property AsFirstStyleEnumerable As IEnumerable(Of Integer)
        Get
            Return New FirstStyleEnumerable(Me)
        End Get
    End Property
End Class

Обратите внимание, что используется структура, а не класс, поскольку использование класса потребует создания нового объекта кучи и добавления дополнительного уровня косвенности к его доступу;настоящая цель структуры - позволить ей реализовать «отличный» IEnumerable от инкапсулированного объекта.Кстати, было бы возможно использовать обобщения с классами маркеров, чтобы избежать необходимости вручную определять новую структуру FirstStyleEnumerator для каждого варианта перечисления.Я не уверен, что это будет чище или более запутанно.

Interface IQualifiedEnumerable(Of T, U)
    Function GetEnumerator() As IEnumerable(Of U)
End Interface

Structure QualifiedEnumerableWrapper(Of T, U)
    Implements IEnumerable(Of U)
    Private myEnumerable As IQualifiedEnumerable(Of T, U)

    Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of U) Implements System.Collections.Generic.IEnumerable(Of U).GetEnumerator
        Return myEnumerable.GetEnumerator
    End Function

    Public Function GetEnumerator1() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
        Return myEnumerable.GetEnumerator
    End Function

    Sub New(ByVal newEnumerable As IQualifiedEnumerable(Of T, U))
        myEnumerable = newEnumerable
    End Sub
End Structure

Class EnumTest2
    Implements IQualifiedEnumerable(Of FirstEnumerationStyle, Integer)
    Implements IQualifiedEnumerable(Of SecondEnumerationStyle, Integer)

    Private Class FirstEnumerationStyle     ' Marker classes for generics
    End Class
    Private Class SecondEnumerationStyle
    End Class

    Private Function GetFirstStyleEnumerator() As System.Collections.Generic.IEnumerable(Of Integer) Implements IQualifiedEnumerable(Of FirstEnumerationStyle, Integer).GetEnumerator
        Return Enumerable.Empty(Of Integer)()
    End Function

    Private Function GetSecondStyleEnumerator() As System.Collections.Generic.IEnumerable(Of Integer) Implements IQualifiedEnumerable(Of SecondEnumerationStyle, Integer).GetEnumerator
        Return Enumerable.Empty(Of Integer)()
    End Function

    Public ReadOnly Property AsFirstStyleEnumerable As IEnumerable(Of Integer)
        Get
            Return New QualifiedEnumerableWrapper(Of FirstEnumerationStyle, Integer)
        End Get
    End Property

    Public ReadOnly Property AsSecondStyleEnumerable As IEnumerable(Of Integer)
        Get
            Return New QualifiedEnumerableWrapper(Of SecondEnumerationStyle, Integer)
        End Get
    End Property
End Class

Здесь определения интерфейса и структуры полностью универсальны;добавление каждого дополнительного метода перечисления в класс потребовало бы добавления функции для возврата ее перечислителя и свойства для возврата QualifiedEnumerableWrapper соответствующего типа.

...