В фреймворковых классах коллекций я часто видел IEnumerator<T>
отдельно реализованный как внутренний класс, и его экземпляр возвращается в методе GetEnumerator
.
Теперь предположим, что я пишу свои собственные классы коллекций, которые будут иметь встроенную коллекцию, такую как List<T>
или T[]
, выступающую в качестве внутреннего держателя, скажем так:
public class SpecialCollection<T> : IEnumerable<T>
{
List<T> list;
public SpecialCollection<T>()
{
}
public IEnumerator<T> GetEnumerator()
{
return list.GetEnumerator();
//or
return list.Where(x => some logic).GetEnumerator();
//or directly rely on yield keyword
yield return x; //etc
}
}
Должен ли я писать свой собственный класс перечислителя или можно вернуть перечислитель класса List<T>
? Есть ли какие-либо обстоятельства, при которых я должен писать свой собственный класс перечислителя?
У меня тоже есть связанный с этим вопрос. Если это не так важно или не имеет большого значения, то почему каждый класс коллекций в BCL пишет свой собственный IEnumerator
?
Например, класс List<T>
имеет что-то вроде
T[] items;
public IEnumerator<T> GetEnumerator()
{
return new List<T>.Enumerator(items);
}
array.Select(x => x).GetEnumerator();
, вы можете использовать((IEnumerable<T>)array).GetEnumerator()
. Одномерные массивы магическим образом реализуют универсальные интерфейсы, которые снаружи выглядят как явная реализация интерфейса. - person Jeppe Stig Nielsen   schedule 10.06.2014// some logic
означало, что в перечислитель можно добавить некоторую дополнительную логику. - person Maarten   schedule 10.06.2014class MyColl : IEnumerable<int>
. Я мог бы хранить свои значения в массиве внутри, поэтому у меня есть полеprivate int[] array;
. Теперь, когда мне нужно реализовать общий интерфейс, я не могу просто сказатьreturn array.GetEnumerator();
(ошибка времени компиляции) из-за не совсем универсального характера массивов (здесьint[]
). Я мог бы решить это наreturn array.Select(x => x).GetEnumerator();
. Но это расточительно. Вместо этого используйтеreturn ((IEnumerable<int>)array).GetEnumerator();
или эквивалентноreturn array.AsEnumerable().GetEnumerator();
. Видишь, что я имею в виду? - person Jeppe Stig Nielsen   schedule 10.06.2014foreach
и почему структура предпочтительнее ссылочного типа. В нем ничего не говорится о повторном использовании существующих реализаций перечислителя. - person nawfal   schedule 10.06.2014List<T>
имеет свой собственный (структурный) тип перечислителя. - person Jon Skeet   schedule 10.06.2014GetEnumerator
резервного массива (о чем мой вопрос). В нем говорится о том, почему в первую очередь требуется структура. Мой вопрос: если вам нужна структура, то почему бы не использовать повторно уже реализованную структуру резервного массива. Я надеюсь, что это ясно. Не хочу придираться, но, честно говоря, ссылка совсем не проясняет моего замешательства. Ответ Эрика делает. - person nawfal   schedule 10.06.2014foreach
над массивом распознается компилятором и вместо этого преобразуется в циклfor
, так как это намного быстрее. Это означает, что на самом деле используются только перечислители упакованных массивов, а действие упаковки также устраняет возможность оптимизации в стиле списка, поэтому массивам не нужно использовать уловку списка, состоящую в том, чтобы иметь структуру в качестве перечислителя (поэтому они нет; их перечислитель -class
), потому что у них есть что-то даже лучше, специфичное для них. - person Servy   schedule 10.06.2014IEnumerator<T>
массива, вы не сможете обнаружить изменение списка между вызовами, что должно вызвать исключение. - person Jon Skeet   schedule 10.06.2014List<T>
,Queue<T>
) в фреймворке — неплохой выбор, учитывая, что они улавливают модификации. - person nawfal   schedule 10.06.2014