28.05.2007, 13:44 | #1 |
Moderator
|
ContainerIterator
Мелочь, а приятно.
Код, который ранее выглядел так: X++: static void test(Args _args) { container con = [1, 12.5, 'test', 2, 3, 'tetst']; int i; ; for (i=1; i<=conlen(con); i++) info(conpeek(con, i)); } X++: static void test4(Args _args) { container con = [1, 12.5, 'test', 2, 3, 'tetst']; gm_containerIterator iterator = new gm_ContainerIterator(con); ; while(iterator.more()) { info(iterator.value()); iterator.next(); } } |
|
|
За это сообщение автора поблагодарили: Gustav (6). |
28.05.2007, 14:07 | #2 |
Участник
|
Итератор мастдай, енумератор - форева.
X++: while(enumerator.moveNext())
info(enumerator.current()); |
|
28.05.2007, 14:09 | #3 |
Участник
|
mfp и соавторы рекомендуют пользоваться энумераторами потому, что:
|
|
28.05.2007, 14:28 | #4 |
Moderator
|
Цитата:
Итератор мастдай, енумератор - форева.
Цитата:
mfp и соавторы рекомендуют пользоваться энумераторами потому, что:
Цитата:
нельзя забыть позвать некст
Меня гораздо больше расстраивает отсутсвие возможности перебрать элеименты любой "коллекции" посредством for each ... in ... |
|
28.05.2007, 14:35 | #5 |
Участник
|
авторы Inside Microsoft Dynamics(TM) AX 4.0
Цитата:
Меня гораздо больше расстраивает отсутсвие возможности перебрать элеименты любой "коллекции" посредством for each ... in ...
Код: [1, 2, 3, 4].each{ x | info(int2str(x));} |
|
28.05.2007, 15:29 | #6 |
Участник
|
Цитата:
или так:
Код: [1, 2, 3, 4].each{ x | info(int2str(x));}
__________________
Бесполезно говорить: «Мы делаем все, что можем». Надо сделать то, что необходимо. |
|
29.05.2007, 08:48 | #7 |
Участник
|
C не причем, с натяжкой - С++
|
|
29.05.2007, 17:18 | #8 |
Moderator
|
Кстати, классический аксаптовский enumerator как раз и не получается, ибо он не предусматривает публичного контейнера и пораждается исключительно методом коллекции getEnumerator(), коего контейнер, естественно, не предоставляет.
|
|
29.05.2007, 17:36 | #9 |
Участник
|
Для пуристов сожно сделать так:
X++: class ContainerCollection { container contents; Enumerator getEnumerator(); } |
|
29.05.2007, 17:49 | #10 |
Moderator
|
А ContainerCollection инициализировать через new() конейнером? Фи... То еще решение....
Хотя.... Можно релизовать методы insert(), delete(), pop(), push() как обертки на conpeek(), conpoke() (которые я постоянно путаю) и получить неплохой класс |
|
31.05.2007, 10:55 | #11 |
Участник
|
|
|
31.05.2007, 12:04 | #12 |
Участник
|
А можно ли попросить написать краткую статью для недогадливых (типа меня) чем отличается енумератор от итератора и зачем они нужны?
|
|
31.05.2007, 13:23 | #13 |
Moderator
|
Цитата:
With reference to: Inside Microsoft Dynamics™ AX 4.0 \Chapter 15. System Classes \The Collection Classes \Traversal Traversal You can traverse your collections by using either an enumerator or an iterator. When the collection classes were first introduced in Dynamics AX, the iterator was the only option. But because of a few obscure drawbacks that appear as hard-to-find errors, enumerators were added, and iterators were kept for backward compatibility. To highlight the subtle differences, the following code shows how to traverse a collection with both approaches. X++: List list = new List(Types::Integer); ListIterator iterator; ListEnumerator enumerator; ; //Populate list. ... //Traverse using an iterator. iterator = new ListIterator(list); while (iterator.more()) { print iterator.value(); iterator.next(); } //Traverse using an enumerator. enumerator = list.getEnumerator(); while (enumerator.moveNext()) { print enumerator.current(); } The first difference is the way in which the iterator and enumerator instances are created. For the iterator, you call new, and for the enumerator, you get an instance from the collection class by calling the getEnumerator method. In most cases, both approaches will work equally well. However, when the collection class resides on the opposite tier from the tier on which it is traversed, the situation is quite different. For example, if the collection resides on the client tier and is traversed on the server tier, the iterator approach fails because the iterator does not support cross-tier referencing. The enumerator does not support cross-tier referencing either, but it doesn't have to because it is instantiated on the same tier as the collection class. Traversing on the server tier using the client tier enumerator is quite network intensive, but the result is logically correct. Because some code is marked as Called From, meaning that it can run on either tier, depending on where it is called from, you could have broken logic if you use iterators, even if you test one execution path. In many cases, hard-to-track bugs such as this surface only when an operation is executed in batch mode. NOTE: In earlier versions of Dynamics AX, this problem was even more pronounced because development and testing sometimes took place in two-tier environments, and this issue surfaces only in three-tier environments. The second difference between iterators and enumerators is the way in which the traversing pointer moves forward. In the iterator approach, you must explicitly call both more and next; in the enumerator approach, the moveNext method handles these needs. Most developers have inadvertently implemented an endless loop at least once, simply because they forgot to move a pointer. This is not a significant problem, but it does cause an annoying interruption during the development phase. If you always use the enumerator, you will not encounter either of the preceding issues. The only situation in which you cannot avoid using the iterator is when you must remove elements from a List collection. The following code shows how this is accomplished. X++: List list = new List(Types::Integer); ListIterator iterator; ; list.addEnd(100); list.addEnd(200); list.addEnd(300); iterator = new ListIterator(list); while (iterator.more()) { if (iterator.value() == 200) iterator.delete(); iterator.next(); } print list.toString(); //{100, 300} pause; |
|
|
За это сообщение автора поблагодарили: MikeR (2). |
31.05.2007, 13:38 | #14 |
Участник
|
Я, кстати, в одной модификашке, чтобы не использовать итераторы (пообащлся на досуге с Максимом) удалял элементы из объекта класса List не чере итераторы, а через контейнеры (преобразование в контейнер, и изменение его содержимого с последующей инициализацей объекта класса List). Кстати, подход заслуживает внимания, так как дает приемущество в скорости удаления.
|
|
31.05.2007, 13:54 | #15 |
Участник
|
Цитата:
Сообщение от Gustav
P.S. Перевод Гугла
А может сделать нормальный перевод? Т.е. главных проблем две: 1. передача данных между клиентом и сервером 2. удаление элементов в энумераторе? |
|
31.05.2007, 13:55 | #16 |
MCT
|
Попробую внести свою лепту. Вот вкратце отличия
1 для того чтоб пользовать iterator его надо инициализить через new() а для enumerator этого не требуется, он использует текущую сущность 2 iterator плохо переносит клиент - серверные пересылы, впрочем как и enumerator но последнему не нужно инициализиться. Поэтому если пользовать iterator могут возникнуть проблемы. 3 это перебор значений в iterator и enumerator. Для enumerator достаточно moveNext() и пойдет перебор а для iterator нужно переводить курсор iterator.next() а многие это пропускают и получается бесконечный цикл. 4 но чтобы удалить значение из списка вам не обойтись без iterator |
|
31.05.2007, 13:56 | #17 |
Участник
|
Цитата:
Сообщение от mazzy
Т.е. главных проблем две:
Сам натыкался на бесконечные циклы из-за этого множество раз. Лечится конечно легко и быстро, но раздражает изрядно. |
|
13.02.2008, 17:00 | #18 |
Moderator
|
Кстати, если к containerEnumerator добавить один метод:
X++: public container enumerate() { return [idx, conpeek(con, idx)]; } X++: items = ['a','b'] for i,thing in enumerate(items): print 'index',i,'contains',thing X++: int idx; ; while(enumerator.moveNext()) { idx++; value = enumerator.current(); } X++: int idx; ; while(enumerator.moveNext()) { [idx, value] = enumerator.enumerate(); } |
|
13.02.2008, 17:23 | #19 |
Участник
|
"You put lipstick on a pig, it's still a pig"
|
|
18.06.2008, 18:36 | #20 |
Участник
|
Цитата:
Сообщение от Gustav
The only situation in which you cannot avoid using the iterator is when you must remove elements from a List collection. The following code shows how this is accomplished.
X++: List list = new List(Types::Integer); ListIterator iterator; ; list.addEnd(100); list.addEnd(200); list.addEnd(300); iterator = new ListIterator(list); while (iterator.more()) { if (iterator.value() == 200) iterator.delete(); iterator.next(); } print list.toString(); //{100, 300} pause; |
|
|
За это сообщение автора поблагодарили: Gustav (2). |