Несколько перечислителей для IEnumerable
У меня есть коллекция, сделанная на заказ, в которой есть много способов генерации объектов.
Он может генерировать все, один объект за раз или N объектов за один раз.
Я хотел бы иметь возможность переключаться между реализациями генерации во время выполнения, и даже, возможно, создавать новые.
Я ищу что-то с таким синтаксисом:
foreach(var obj in myCollection.EnumerateAs(new LazyEnumerator())
{
// ...
}
Мои проблемы:
Я не знаю что EnumerateAs()
вернуть? Я предполагаю, что это IEnumerator, но будет ли он по-прежнему перечислителем моего списка?
LazyEnumerator наследуется от IEnumerator?
Как он узнал о myCollection?
3 ответа
Возвращаемое значение вашего EnumerateAs()
должно быть IEnumerable<T>
где T - тип объекта, который содержится в вашей коллекции. Я рекомендую прочитать больше о доходности, поскольку это может помочь вам понять, как работает перечисление. Класса по умолчанию для предоставления перечисления "стратегия" не существует, но вы можете легко реализовать что-то вроде этого, используя возвращение урожая для базовой коллекции различными способами.
Из вашего вопроса неясно, как стратегии перечисления будут взаимодействовать с вашим классом коллекции. Похоже, что вы могли бы после чего-то вроде:
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>>
, но приведенный выше наиболее точно соответствует желаемому синтаксису.
Я бы посоветовал вам начать с создания функций GetEnumeratorInFirstStyle, GetEnumeratorInSecondStyle и т. Д. (Конечно, используйте имена, подходящие для вашего приложения), а затем создайте новые структуры, например (например, в синтаксисе vb, но они должны быть легко конвертируемыми в C#):
Класс enumTest Функция GetEnumeratorInFirstStyle() As IEnumerator(Of Integer) Return Enumerable.Empty(Of Integer)() 'Реальный код сделает что-то лучше Конечная функция Частная структура FirstStyleEnumerable Реализует IEnumerable(Of Integer) Приватный myEnumTest As enumTest Открытая функция GetEnumerator() As System.Collections.Generic.IEnumerator(Of Integer) Реализует System.Collections.Generic.IEnumerable(Of Integer).GetEnumerator Вернуть myEnumTest.GetEnumeratorInFirstStyle Конечная функция Открытая функция GetEnumerator1() As System.Collections.IEnumerator Реализует System.Collections.IEnumerable.GetEnumerator Вернуть myEnumTest.GetEnumeratorInFirstStyle Конечная функция Sub New(ByVal newEnumTest As enumTest) myEnumTest = newEnumTest End Sub Конечная структура Открытое свойство ReadOnly AsFirstStyleEnumerable As IEnumerable(Of Integer) Получить Возврат нового FirstStyleEnumerable(Me) Конец получить Конечная недвижимость Конечный класс
Обратите внимание, что используется структура, а не класс, поскольку использование класса потребует создания нового объекта кучи и добавления дополнительного уровня косвенности к его доступу; реальная цель структуры - позволить ей реализовать "отличный" IEnumerable
Интерфейс IQualifiedEnumerable(Of T, U) Функция GetEnumerator () как IEnumerable(Of U) Конец интерфейса Структура QualifiedEnumerableWrapper(Of T, U) Реализует IEnumerable(Of U) Приватный myEnumerable As IQualifiedEnumerable(Of T, U) Открытая функция GetEnumerator() As System.Collections.Generic.IEnumerator(Of U) Реализует System.Collections.Generic.IEnumerable(Of U).GetEnumerator Вернуть myEnumerable.GetEnumerator Конечная функция Открытая функция GetEnumerator1() As System.Collections.IEnumerator Реализует System.Collections.IEnumerable.GetEnumerator Вернуть myEnumerable.GetEnumerator Конечная функция Sub New(ByVal newEnumerable As IQualifiedEnumerable(Of T, U)) myEnumerable = newEnumerable End Sub Конечная структура Класс EnumTest2 Реализует IQualifiedEnumerable(Of FirstEnumerationStyle, Integer) Реализует IQualifiedEnumerable(Of SecondEnumerationStyle, Integer) Частный класс FirstEnumerationStyle 'Маркерные классы для обобщений Конечный класс Частный класс SecondEnumerationStyle Конечный класс Закрытая функция GetFirstStyleEnumerator() как System.Collections.Generic.IEnumerable(Of Integer) Реализует IQualifiedEnumerable(Of FirstEnumerationStyle, Integer).GetEnumerator Вернуть Enumerable.Empty (Of Integer) () Конечная функция Закрытая функция GetSecondStyleEnumerator() как System.Collections.Generic.IEnumerable(Of Integer) Реализует IQualifiedEnumerable(Of SecondEnumerationStyle, Integer).GetEnumerator Вернуть Enumerable.Empty (Of Integer) () Конечная функция Открытое свойство ReadOnly AsFirstStyleEnumerable As IEnumerable(Of Integer) Получить Возврат нового QualifiedEnumerableWrapper(Of FirstEnumerationStyle, Integer) Конец получить Конечная недвижимость Открытое свойство ReadOnly AsSecondStyleEnumerable As IEnumerable(Of Integer) Получить Возврат нового QualifiedEnumerableWrapper(Of SecondEnumerationStyle, Integer) Конец получить Конечная недвижимость Конечный класс
Здесь определения интерфейса и структуры полностью универсальны; добавление каждого дополнительного метода перечисления в класс потребовало бы добавления функции для возврата ее перечислителя и свойства для возврата QualifiedEnumerableWrapper соответствующего типа.
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
очень гибкий