Перейти к содержимому

Getenumerator c как реализовать

  • автор:

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]; > > >

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 < private Sport_car[] car_list; IEnumeratorIEnumerable.GetEnumerator() < return (IEnumerator)car_list.GetEnumerator(); > IEnumerator IEnumerable.GetEnumerator() < return car_list.GetEnumerator(); >..

20 янв 2012 в 23:09

Пишет , что использование универсального типа «System.Collection.Generic.IEnumerator» требует аргумента типа «1» То есть нельзя даже просто написать 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(); >> 

Stack.IEnumerable. Get Enumerator Method

Some information relates to prerelease product that may be substantially modified before it’s released. Microsoft makes no warranties, express or implied, with respect to the information provided here.

Returns an enumerator that iterates through a collection.

 virtual System::Collections::IEnumerator ^ System.Collections.IEnumerable.GetEnumerator() = System::Collections::IEnumerable::GetEnumerator;
System.Collections.IEnumerator IEnumerable.GetEnumerator ();
abstract member System.Collections.IEnumerable.GetEnumerator : unit -> System.Collections.IEnumerator override this.System.Collections.IEnumerable.GetEnumerator : unit -> System.Collections.IEnumerator
Function GetEnumerator () As IEnumerator Implements IEnumerable.GetEnumerator
Returns

An IEnumerator that can be used to iterate through the collection.

Implements

Remarks

The foreach statement of the C# language ( for each in C++, For Each in Visual Basic) hides the complexity of the enumerators. Therefore, using foreach is recommended, instead of directly manipulating the enumerator.

Enumerators can be used to read the data in the collection, but they cannot be used to modify the underlying collection.

Initially, the enumerator is positioned before the first element in the collection. Reset also brings the enumerator back to this position. At this position, Current is undefined. Therefore, you must call MoveNext to advance the enumerator to the first element of the collection before reading the value of Current.

Current returns the same object until either MoveNext or Reset is called. MoveNext sets Current to the next element.

If MoveNext passes the end of the collection, the enumerator is positioned after the last element in the collection and MoveNext returns false . When the enumerator is at this position, subsequent calls to MoveNext also return false . If the last call to MoveNext returned false , Current is undefined. To set Current to the first element of the collection again, you can call Reset followed by MoveNext.

An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and the next call to MoveNext or Reset throws an InvalidOperationException.

The enumerator does not have exclusive access to the collection; therefore, enumerating through a collection is intrinsically not a thread-safe procedure. To guarantee thread safety during enumeration, you can lock the collection during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization.

Default implementations of collections in System.Collections.Generic are not synchronized.

This method is an O(1) operation.

Applies to

See also

  • GetEnumerator()
  • GetEnumerator()
  • IEnumerator

IEnumerable. Get Enumerator Метод

Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

Возвращает перечислитель, который осуществляет итерацию по коллекции.

public: System::Collections::IEnumerator ^ GetEnumerator();
public System.Collections.IEnumerator GetEnumerator ();
abstract member GetEnumerator : unit -> System.Collections.IEnumerator
Public Function GetEnumerator () As IEnumerator
Возвращаемое значение

Объект IEnumerator, который используется для прохода по коллекции.

Примеры

В следующем примере кода демонстрируется реализация IEnumerable интерфейсов для пользовательской коллекции. В этом примере GetEnumerator не вызывается явным образом, но реализуется для поддержки foreach использования ( For Each в Visual Basic). Этот пример кода является частью более крупного примера для IEnumerable интерфейса .

using System; using System.Collections; // Simple business object. public class Person < public Person(string fName, string lName) < this.firstName = fName; this.lastName = lName; >public string firstName; public string lastName; > // Collection of Person objects. This class // implements IEnumerable so that it can be used // with ForEach syntax. public class People : IEnumerable < private Person[] _people; public People(Person[] pArray) < _people = new Person[pArray.Length]; for (int i = 0; i < pArray.Length; i++) < _people[i] = pArray[i]; >> // Implementation for the GetEnumerator method. IEnumerator IEnumerable.GetEnumerator() < return (IEnumerator) GetEnumerator(); >public PeopleEnum GetEnumerator() < return new PeopleEnum(_people); >> // When you implement IEnumerable, you must also implement IEnumerator. public class PeopleEnum : IEnumerator < public Person[] _people; // Enumerators are positioned before the first element // until the first MoveNext() call. int position = -1; public PeopleEnum(Person[] list) < _people = list; >public bool MoveNext() < position++; return (position < _people.Length); >public void Reset() < position = -1; >object IEnumerator.Current < get < return Current; >> public Person Current < get < try < return _people[position]; >catch (IndexOutOfRangeException) < throw new InvalidOperationException(); >> > > class App < static void Main() < Person[] peopleArray = new Person[3] < new Person("John", "Smith"), new Person("Jim", "Johnson"), new Person("Sue", "Rabon"), >; People peopleList = new People(peopleArray); foreach (Person p in peopleList) Console.WriteLine(p.firstName + " " + p.lastName); > > /* This code produces output similar to the following: * * John Smith * Jim Johnson * Sue Rabon * */ 
Imports System.Collections ' Simple business object. Public Class Person Public Sub New(ByVal fName As String, ByVal lName As String) Me.firstName = fName Me.lastName = lName End Sub Public firstName As String Public lastName As String End Class ' Collection of Person objects, which implements IEnumerable so that ' it can be used with ForEach syntax. Public Class People Implements IEnumerable Private _people() As Person Public Sub New(ByVal pArray() As Person) _people = New Person(pArray.Length - 1) <> Dim i As Integer For i = 0 To pArray.Length - 1 _people(i) = pArray(i) Next i End Sub ' Implementation of GetEnumerator. Public Function GetEnumerator() As IEnumerator _ Implements IEnumerable.GetEnumerator Return New PeopleEnum(_people) End Function End Class ' When you implement IEnumerable, you must also implement IEnumerator. Public Class PeopleEnum Implements IEnumerator Public _people() As Person ' Enumerators are positioned before the first element ' until the first MoveNext() call. Dim position As Integer = -1 Public Sub New(ByVal list() As Person) _people = list End Sub Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext position = position + 1 Return (position < _people.Length) End Function Public Sub Reset() Implements IEnumerator.Reset position = -1 End Sub Public ReadOnly Property Current() As Object Implements IEnumerator.Current Get Try Return _people(position) Catch ex As IndexOutOfRangeException Throw New InvalidOperationException() End Try End Get End Property End Class Class App Shared Sub Main() Dim peopleArray() As Person = < _ New Person("John", "Smith"), _ New Person("Jim", "Johnson"), _ New Person("Sue", "Rabon")>Dim peopleList As New People(peopleArray) Dim p As Person For Each p In peopleList Console.WriteLine(p.firstName + " " + p.lastName) Next End Sub End Class ' This code produces output similar to the following: ' ' John Smith ' Jim Johnson ' Sue Rabon 

Комментарии

Инструкция foreach языка C# ( For Each в Visual Basic) позволяет скрыть сложный механизм перечислителей. Поэтому рекомендуется вместо непосредственного использования перечислителя применять ключевое слово foreach .

Перечислители могут использоваться для чтения данных в коллекции, но не для ее изменения.

Изначально перечислитель располагается перед первым элементом коллекции. Метод Reset также возвращает перечислитель в эту позицию. В этой позиции Current свойство не определено. Поэтому необходимо вызвать MoveNext метод , чтобы перейти перечислитель к первому элементу коллекции, прежде чем считывать значение Current.

Current возвращает тот же объект, пока не будет вызван метод MoveNext или Reset. MoveNext задает Current в качестве значения для следующего элемента.

Если MoveNext передает конец коллекции, перечислитель располагается после последнего элемента в коллекции и MoveNext возвращает . false Если перечислитель находится в этой позиции, последующие вызовы также MoveNext возвращают false . Если последний вызов возвращает MoveNext false , Current значение не определено. Чтобы снова задать в качестве значения свойства Current первый элемент коллекции, можно последовательно вызвать методы Reset иMoveNext.

Если в коллекцию вносятся изменения, такие как добавление, изменение или удаление элементов, поведение перечислителя не определено.

У перечислителя нет эксклюзивного доступа к коллекции, поэтому перечисление коллекции не является потокобезопасной процедурой. Чтобы гарантировать потокобезопасность, можно заблокировать коллекцию на время всего перечисления. Чтобы разрешить доступ к коллекции из нескольких потоков для чтения и записи, необходимо реализовать собственную синхронизацию.

Применяется к

См. также раздел

  • IEnumerator
  • Итераторы (C#)
  • Итераторы (Visual Basic)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *