Getenumerator c как реализовать
Как мы увидели, основной для большинства коллекций является реализация интерфейсов IEnumerable и IEnumerator. Благодаря такой реализации мы можем перебирать объекты в цикле foreach :
foreach(var item in перечислимый_объект)
Перебираемая коллекция должна реализовать интерфейс IEnumerable.
Интерфейс IEnumerable имеет метод, возвращающий ссылку на другой интерфейс — перечислитель:
public interface IEnumerable
А интерфейс IEnumerator определяет функционал для перебора внутренних объектов в контейнере:
public interface IEnumerator < bool MoveNext(); // перемещение на одну позицию вперед в контейнере элементов object Current // текущий элемент в контейнере void Reset(); // перемещение в начало контейнера >
Метод MoveNext() перемещает указатель на текущий элемент на следующую позицию в последовательности. Если последовательность еще не закончилась, то возвращает true. Если же последовательность закончилась, то возвращается false.
Свойство Current возвращает объект в последовательности, на который указывает указатель.
Метод Reset() сбрасывает указатель позиции в начальное положение.
Каким именно образом будет осуществляться перемещение указателя и получение элементов зависит от реализации интерфейса. В различных реализациях логика может быть построена различным образом.
Например, без использования цикла foreach перебирем массив с помощью интерфейса IEnumerator:
using System.Collections; string[] people = ; IEnumerator peopleEnumerator = people.GetEnumerator(); // получаем IEnumerator while (peopleEnumerator.MoveNext()) // пока не будет возвращено false < string item = (string)peopleEnumerator.Current; // получаем элемент на текущей позиции Console.WriteLine(item); >peopleEnumerator.Reset(); // сбрасываем указатель в начало массива
Реализация IEnumerable и IEnumerator
Рассмотрим простешую реализацию IEnumerable на примере:
using System.Collections; Week week = new Week(); foreach (var day in week) < Console.WriteLine(day); >class Week : IEnumerable < string[] days = < "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" >; public IEnumerator GetEnumerator() => days.GetEnumerator(); >
В данном случае класс Week, который представляет неделю и хранит все дни недели, реализует интерфейс IEnumerable. Однако в данном случае мы поступили очень просто — вместо реализации IEnumerator мы просто возвращаем в методе GetEnumerator объект IEnumerator для массива.
public IEnumerator GetEnumerator() => days.GetEnumerator();
Благодаря этому мы можем перебрать все дни недели в цикле foreach.
В то же время стоит отметить, что для перебора коллекции через foreach в принципе необязательно реализовать интерфейс IEnumerable. Достаточно в классе определить публичный метод GetEnumerator , который бы возвращал объект IEnumerator. Например:
class Week < string[] days = < "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" >; public IEnumerator GetEnumerator() =>days.GetEnumerator(); >
Однако это было довольно просто — мы просто используем уже готовый перчислитель массива. Однако, возможно, потребуется задать свою собственную логику перебора объектов. Для этого реализуем интерфейс IEnumerator :
using System.Collections; class WeekEnumerator : IEnumerator < string[] days; int position = -1; public WeekEnumerator(string[] days) =>this.days = days; public object Current < get < if (position == -1 || position >= days.Length) throw new ArgumentException(); return days[position]; > > public bool MoveNext() < if (position < days.Length - 1) < position++; return true; >else return false; > public void Reset() => position = -1; > class Week < string[] days = < "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" >; public IEnumerator GetEnumerator() => new WeekEnumerator(days); >
Здесь теперь класс Week использует не встроенный перечислитель, а WeekEnumerator, который реализует IEnumerator.
Ключевой момент при реализации перечислителя — перемещения указателя на элемент. В классе WeekEnumerator для хранения текущей позиции определена переменная position. Следует учитывать, что в самом начале (в исходном состоянии) указатель должен указывать на позицию условно перед первым элементом. Когда будет производиться цикл foreach, то данный цикл вначале вызывает метод MoveNext и фактически перемещает указатель на одну позицию в перед и только затем обращается к свойству Current для получения элемента в текущей позиции.
Затем в программе мы можем аналогичным образом перебирать объект Week с помощью цикла foreach:
Week week = new Week(); foreach(var day in week)
Обобщенная версия IEnumerator
В примерах выше использовались необобщенные версии интерфейсов, однако мы также можем использовать их обобщенные двойники:
using System.Collections; class WeekEnumerator : IEnumerator < string[] days; int position = -1; public WeekEnumerator(string[] days) =>this.days = days; public string Current < get < if (position == -1 || position >= days.Length) throw new ArgumentException(); return days[position]; > > object IEnumerator.Current => Current; public bool MoveNext() < if (position < days.Length - 1) < position++; return true; >else return false; > public void Reset() => position = -1; public void Dispose() < >> class Week < string[] days = < "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" >; public IEnumerator GetEnumerator() => new WeekEnumerator(days); >
В данном случае реализуем интерфейс IEnumerator , соответственно в свойстве Current нам надо возвратить объект string. В этом случае при переборе в цикле foreach перебираемые объекты будут автоматически представлять тип string :
Week week = new Week(); foreach (string day in week)
IEnumerable , C#
Компилятор упорно выдает ошибку : . не реализуется член интерфейса «System.Collections.IEnumerable.GetEnumerator()» Не совсем понятно , как можно реализовать метод IEnumerable.GetEnumerator() ведь IEnumerable обобщенный интерфейс и нужно указывать тип коллекции(что я и делал). Заранее спасибо.
Отслеживать
задан 20 янв 2012 в 21:10
370 1 1 золотой знак 12 12 серебряных знаков 33 33 бронзовых знака
Понимаете в том то и дело : я пробовал реализовать 2-ой метод ,но компилятор сразу красным подчеркивает слово IEnumerator , если не указывать тип T . Наверное нагляднее будет конкретный кусок кода показать : public class garage : IEnumerable
20 янв 2012 в 23:09
Пишет , что использование универсального типа «System.Collection.Generic.IEnumerator
20 янв 2012 в 23:16
Исправьте IEnumerator на System.Collections.IEnumerator , либо добавьте соответствующий using . Inumerator и IEnumerator
20 янв 2012 в 23:59
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Интерфейс, к-й вы реализуете в свою очередь реализует не типизированный IEnumerable:
public interface IEnumerable : IEnumerable < IEnumeratorGetEnumerator(); > public interface IEnumerator : IDisposable, IEnumerator < T Current < get; >> public interface IEnumerator < object Current < get; >bool MoveNext(); void Reset(); >
Следовательно вам необходимо реализовать и его «внутренности», а именно еще один метод GetEnumerator() и IEnumerator:
using System.Collections; using System.Collections.Generic; public class GarageEnumerator : IEnumerator < private readonly IEnumerator enumerator; public GarageEnumerator(IEnumerator enumerator) < this.enumerator = enumerator; >public void Dispose() < >public bool MoveNext() < return enumerator.MoveNext(); >public void Reset() < enumerator.Reset(); >public T Current < get < return (T)enumerator.Current; >> object IEnumerator.Current < get < return Current; >> > public class Garage : IEnumerable < private readonly T[] carList; //initialization ! public IEnumeratorGetEnumerator() < return new GarageEnumerator(carList.GetEnumerator()); > IEnumerator IEnumerable.GetEnumerator() < return GetEnumerator(); >>
А вообще пользуйтесь встроенными средствами в VS — она может сделать ето за вас.
UPDATE: начиная с 3.5 фреймворка можно подключить:
using System.Linq;
public class Garage : IEnumerable < private readonly T[] carList = new T[10]; //initialization ! public IEnumeratorGetEnumerator() < return carList.Cast().GetEnumerator(); > IEnumerator IEnumerable.GetEnumerator() < return GetEnumerator(); >>
Getenumerator c как реализовать
Коллеги, хотел бы реализовать на С++ COM объект, который можно было бы в C# обойти с помощью foreach
Нашел статью http://www.rsdn.ru/article/com/comcoll.xml
Автор(ы): Владислав Чистяков
Но когда так реализовал, у меня компилятор стал жаловаться, что в моём объекте нет GetEnumerator, когда его добавил, стал жаловаться на отсутвие MoveNext.
Мне кажется, я куда-то не туда копаю.
Вопрос простой — как на С++ релизовать нечто, что можно будет в C# обойти с помощью foraech
Заранее спасибо.
Re: Реализация foreach
| От: | Rakafon | http://rakafon.blogspot.com/ |
| Дата: | 28.12.10 08:31 | |
| Оценка: |
Здравствуйте, Аноним, Вы писали:
А>Вопрос простой — как на С++ релизовать нечто, что можно будет в C# обойти с помощью foraech
А>Заранее спасибо.
Написать это «нечно» на managed C++, ведь всё равно, кроме как в .NET это нигде не заюзать.
«Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы.» (c) Мейер Ансельм Ротшильд , банкир.
Re[2]: Реализация foreach
| От: | Artem.shi |
| Дата: | 28.12.10 08:55 |
| Оценка: |
Здравствуйте, Rakafon, Вы писали:
R>Написать это «нечно» на managed C++, ведь всё равно, кроме как в .NET это нигде не заюзать.
Я это и пытаюсь сделать.
Не пойму, зачем нужен метод GetEnumerator, и какого типа данные он должен возвращать.
Судя по документации, итератор ходит с помощью MoveNext, Reset? Current и Count.
http://msdn.microsoft.com/ru-ru/library/system.collections.ienumerable.getenumerator(v=VS.90).aspx?appId=Dev10IDEF1&l=RU-RU&k=k(IENUMERABLE);k(DevLang-«C++»);k(TargetOS-WINDOWS)&rd=true
Re[3]: Реализация foreach
| От: | dcb-BanDos | |
| Дата: | 28.12.10 10:15 | |
| Оценка: | 1 (1) | |
Здравствуйте, Artem.shi, Вы писали:
AS>Здравствуйте, Rakafon, Вы писали:
Переложи на COM подобный код:
using System.Collections; // Declare the Tokens class: public class Tokens : IEnumerable < private string[] elements; Tokens(string source, char[] delimiters) < // Parse the string into tokens: elements = source.Split(delimiters); > // IEnumerable Interface Implementation: // Declaration of the GetEnumerator() method // required by IEnumerable public IEnumerator GetEnumerator() < return new TokenEnumerator(this); > // Inner class implements IEnumerator interface: private class TokenEnumerator : IEnumerator < private int position = -1; private Tokens t; public TokenEnumerator(Tokens t) < this.t = t; > // Declare the MoveNext method required by IEnumerator: public bool MoveNext() < if (position < t.elements.Length - 1) < position++; return true; > else < return false; > > // Declare the Reset method required by IEnumerator: public void Reset() < position = -1; >// Declare the Current property required by IEnumerator: public object Current < get < return t.elements[position]; > > >
Ничто не ограничивает полет мысли программиста так, как компилятор.
Re[4]: Реализация foreach
| От: | Artem.shi |
| Дата: | 28.12.10 11:41 |
| Оценка: |
Здравствуйте, dcb-BanDos, Вы писали:
Спасибо, в принципи, такой вариант меня устраивает.
StringList GetEnumerator — метод
Gets an enumerator that iterates through the elements of the collection.
Пространство имён: Tessa.Exchange.WebServices.Data
Сборка: Tessa.Server (в Tessa.Server.dll) Версия: 3.5.0.19
![]()
Синтаксис
public IEnumeratorstring> GetEnumerator()
Public Function GetEnumerator As IEnumerator(Of String)
public: virtual IEnumeratorString^>^ GetEnumerator() sealed
abstract GetEnumerator : unit -> IEnumeratorstring> override GetEnumerator : unit -> IEnumeratorstring>
Возвращаемое значение
Тип: IEnumerator String
An IEnumerator for the collection.
Реализации
![]()
См. также