В рамковите класове на колекции често съм виждал 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>
има свой собствен тип (struct) изброител. - person Jon Skeet   schedule 10.06.2014GetEnumerator
на резервния масив (за което е въпросът ми). Той говори за това защо се изисква да бъде struct на първо място. Въпросът ми е, ако имате нужда от структура, тогава защо не използвате отново вече внедрената структура на резервен масив. Надявам се да е ясно. Не за да се заяждам, но честно казано връзката изобщо не изяснява объркването ми. Отговорът на Ерик го прави. - 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