You are on page 1of 9

Por Mario del Valle y Miguel Katrib Grupo Weboo Universidad de La Habana

Enumeradores e Iteradores en C# y C# 2.0


El patrn Enumerador en C#
En C# si una clase quiere permitir una iteracin sobre elementos contenidos en una instancia de la misma, o "producidos" de algn modo a partir de dicha instancia, la clase debe implementar el patrn enumerador. Este patrn est tipificado en .NET por la interface IEnumerator.
interface IEnumerator{ bool MoveNext(); object Current{get;} void Reset(); }

<<

<<

En este trabajo se ilustra la utilidad de los enumeradores y del ciclo foreach en C#. Se analizan cules son las limitaciones de estos enumeradores que justifican la importancia de la nueva inclusin de iteradores en el venidero C# 2.0. Se ejemplifican las ventajas de estos iteradores en C# 2.0 para escribir cdigo ms elegante, legible y menos propenso a errores. Finalmente se proporciona una implementacin de iteradores por medio de hebras que, adems de ilustrar la utilizacin de las hebras, ofrece una forma concreta de usar iteradores en el actual C#.

De este modo si una clase C implementa


IEnumerator
class C: IEnumerator{ }

Entonces sobre un objeto c de tipo C se puede hacer la siguiente iteracin


C c = new C(); while (c.MoveNext()) { Process c.Current }

El mtodo Reset permite que haciendo c.Reset() se deje disponible a c para una nueva iteracin. En este sentido una instancia de C hace las veces de coleccin porque se pueden recorrer los elementos de C siguiendo el patrn anterior.

Colecciones Virtuales
La coleccin de elementos a recorrer a travs del enumerador puede ser virtual, es decir

25

<<dotNetMana

<< dnm.plataforma
los elementos que se procesan como resultado de la iteracin no tienen que estar fsicamente contenidos en una estructura contenedor (sea un array, una lista, etc). Por ejemplo con la siguiente clase se permitira recorrer los enteros pares de un intervalo.
class EvenEnumerator: IEnumerator { bool moveOK; int currentValue, lower, upper; public EvenEnumerator(int lowerBound, int upperBound) { if (lowerBound > upperBound) throw new ArgumentException( Wrong interval); if (lowerBound % 2 != 0) lower = lowerBound-1; else lower = lowerBound 2; upper = upperBound; Reset(); } public bool MoveNext() { if (currentValue > upper) return false; currentValue = currentValue+2; moveOK = currentValue<=upper; return moveOK; } public object Current{ get { if (moveOK) return currentValue; else throw new InvalidOperationException( There is no current element); } } public void Reset() { moveOK = false; currentValue = lower; } }

El ciclo foreach
Asociado al patrn enumerador C# ofrece un recurso importante: el ciclo foreach. Si una clase Items implementa la interface IEnumerable
interface IEnumerable{ IEnumerator GetEnumerator(); } class Items: IEnumerable{ }

O simplemente implementa un mtodo de signatura IEnumerator

pues nos protegemos de errores en la inicializacin de la variable de control del ciclo for (derecha), la pregunta de control y el incremento de la variable. El azcar sintctico que nos ofrece este ciclo foreach aumenta la productividad, previene cometer errores por un uso inadecuado de los patrones tradicionales y favorece la escritura de un cdigo ms elegante. Sin embargo, desafortunadamente C# no introduce una notacin similar para ser utilizada en expresiones lgicas (de tipo bool). Podra ser muy til disponer de dos operadores lgicos como:

foreach(object x in list) { ... Process x }

IEnumerator e = list.GetEnumerator(); while(e.MoveNext()) { object x = e.Current; ... Process x; } Tabla1. Cdigo generado para el ciclo foreach

GetEnumerator() entonces sobre un objeto list de tipo Items se puede hacer

un recorrido como se denota en el cdigo a la izquierda (tabla 1) para el cual el

forall (object x in list): <expresin bool que usa a x> exist (object x in list): <expresin bool que usa a x>

T[] list = new T[10]; for (int i=0; i<list.Length; i++) { ... Process list[i] }

T[] list = new T[10]; for (int i=0; i<list.Length; i++) { ... Process list[i] } Tabla2. Ciclos foreach y for sobre un array

<<dotNetMana

Para apreciar mejor la utilidad del recurso de iteracin que se propondr ms adelante es importante comprender este concepto de que los elementos que se recorren en una iteracin no tienen que haber sido previamente almacenados fsicamente en alguna parte.

compilador lo expandir en un cdigo equivalente al cdigo a la derecha. Los arrays (la familiar construccin primitiva para almacenar colecciones de elementos) pueden ser tratados tambin con un ciclo foreach (Tabla 2 cdigo a la izquierda) en lugar del tradicional ciclo for (Tabla 2 cdigo a la derecha) De este modo si no nos interesase la posicin de los elementos dentro del array es ms cmodo y seguro recorrerlos con el ciclo foreach (izquierda)

Tales recursos, unidos a las capacidades de atributos, reflection y CodeDom podra aumentar las capacidades de C# como lenguaje no slo de implementacin sino tambin de especificacin1.

Limitaciones del patrn enumerador


Implementar un recorrido con el patrn enumerador es relativamente simple cuando se hace un recorrido secuencial sobre un contenedor como

1 La inclusin de un recurso de este estilo ser tratado por los autores en un prximo trabajo para incluir aserciones lgicas en C#.

26

<< dnm.plataforma
un array o una lista, o cuando se recorre una coleccin virtual simple como la del caso de intervalo de nmeros pares ilustrado anteriormente. En cualquier caso la implementacin del par MoveNext-Current dentro del enumerador debe mantener el estado interno del recorrido entre una llamada a MoveNext y otra, de manera de poder retomar este estado en cada nueva llamada. Mantener tal estado no es nada simple cuando se quiere hacer un recorrido recursivo complicado sobre una estructura como un rbol o para una coleccin virtual que produce sus elementos por algn algoritmo recursivo (por ejemplo los movimientos de los discos del juego de las Torres de Hanoi, lo que se ver en el ejemplo de la seccin final). Considere a continuacin una versin simplificada de una clase Tree
class Tree { object nodeValue; public ArrayList Nodes { get{} } }

nos devuelva los nodos del rbol en preorden. Una solucin simple podra ser:
class Tree { object nodeValue; public ArrayList Nodes { get{} } public IEnumerable NodesInPreOrder { get { ArrayList nodes = new ArrayList(); ListInPreOrder(this, nodes); return nodes; } } private void ListInPreOrder(Tree t, ArrayList nodes) { nodes.Add(t.nodeValue); foreach (Tree t1 in t.Nodes) ListInPreOrder(t1, nodes); } }

Si se quisieran listar en preorden los elementos de un rbol se podra incluir dentro de la clase un mtodo ListInPreOrder.
class Tree { object nodeValue; public ArrayList Nodes { get{} } public void ListInPreOrder() { ListInPreOrder(this); } private void ListInPreOrder(Tree t) { Console.WriteLine( t.nodeValue.ToString()); foreach (Tree t1 in t.Nodes) ListInPreOrder(t1); } }

Sin embargo, esta solucin tiene el inconveniente que obliga a colocar todos los nodos en un contenedor fsico (ArrayList en este caso) para luego recorrer dicho contenedor. Esto no es una solucin muy eficiente, ms an si es posible que el cdigo cliente (como se muestra a continuacin) puede decidir abortar el recorrido porque en este caso de todos modos el verdadero recorrido de los nodos en el rbol ya se habra realizado.
Tree t = new Tree(); ... foreach (object x in t.NodesInPreOrder) { if (some condition on x) break; else ...Process x ... }

Como se puede observar este recorrido usando la recursin es muy simple pero fuerza a que el procesamiento a realizar con los elementos (listarlos en este caso) est encapsulado dentro de la clase Tree. Para dar ms facilidad a que sea el cdigo cliente el que decida qu quiere hacer con los elementos que recorre en un determinado orden, sera deseable tener dentro de la clase Tree un enumerador que

Otra solucin sera programar directamente el enumerador, pero en este caso habra que implementar el mantener el estado interno del recorrido recursivo. Una implementacin para este caso se muestra a continuacin. Note la complicacin del cdigo porque para conservar el estado de la iteracin en preorden, entre una llamada a MoveNext y otra, ha sido necesario utilizar una pila como estructura auxiliar.

27

<<dotNetMana

class Tree { object nodeValue; public ArrayList Nodes {

<< dnm.plataforma
get{} } public IEnumerable NodesInPreOrder { get { return new PreOrderEnumerable(this);} } //Inner class class PreOrderEnumerable:IEnumerable { Tree t; public PreOrderEnumerable(Tree t){this.t=t;} public IEnumerator GetEnumerator() { return new PreOrderEnumerator(t); } class PreOrderEnumerator: IEnumerator { Tree t; Stack s; object current; bool moveOK; public PreOrderEnumerator(Tree t) { if (t==null) throw new InvalidArgumentException( Null parameter); this.t=t; s = new Stack(); Reset(); } public bool MoveNext() { if (s.Empty) return false; else { Tree t = s.Pop(); current = t.nodeValue; moveOK = true; if (t.Nodes!=null) for (int k = t.Nodes.Count-1; k>=0, k) s.Push(t.Nodes[k]); return moveOK; } } public object Current { if (moveOK) return current; else throw new InvalidOperationException( Enumeration is out of limits); } public void Reset() { s.Clear(); s.Push(t); } } } }

Nueva inclusin de Iteradores en C# 2.0!


Inspirados en lenguajes como CLU, Sather y otros, el venidero C# 2.0 [1] incluir un recurso muy til de programacin: iteradores (iterators)2. Con ello se facilitar la forma en que se itera sobre una coleccin de elementos a travs de una instruccin foreach. Note, con el ejemplo de recorrido de los nodos de un rbol (seccin anterior), que dependiendo de la complejidad del algoritmo de recorrido (que puede incluir recursividad), implementar el mecanismo para conservar el estado de la iteracin con los mtodos MoveNext y Current puede resultar bastante complicado (y por consiguiente menos elegante, menos legible y ms propenso a errores). El nuevo recurso de iterador en C# 2.0 permite solucionar inconvenientes como ste. Un iterador servir de contraparte de un ciclo foreach. Se considerar un iterador a un mtodo que devuelva un IEnumerable o un IEnumerator y que inclu-

Inspirados en lenguajes como CLU, Sather y otros, el venidero C# 2.0 [1] incluir un recurso muy til de programacin: iteradores

ya en su definicin la utilizacin de una operacin especial yield return expresin. Este operador yield actuar como un return pero con la diferencia de que al volver a invocarse al mtodo, como consecuencia de un nuevo paso en la iteracin del ciclo foreach, la ejecucin del mtodo empezar a continuacin del ltimo yield return. En este sentido el mtodo que incluye el yield actuar como corutina de quien lo llam. De este modo la definicin de un iterador para recorrer el rbol en preorden puede ser
class Tree: IEnumerable { object nodeValue; public ArrayList Nodes { get{...} } ... public IEnumerator GetEnumerator()

<<dotNetMana

2 Tambin habamos propuesto una idea similar para incluir iteradores en el lenguaje Eiffel (ver [2], [3])

28

<< dnm.plataforma
{ yield nodeValue; foreach (Tree t in Nodes) foreach (object x in t) yield return x; } }

De este modo un rbol t se podra recorrer fcilmente de los dos modos:


foreach (object x in t.PreOrder)

y
foreach (object x in t.PostOrder)

public IEnumerable PostOrder { get { return new PostOrderEnumerable(this); } } class PostOrderEnumerable:IEnumerable { Tree t; public new PostOrderEnumerable(Tree t) { this.t=t; } public IEnumerator GetEnumerator() { return new PostOrderEnumerator(t); } } class PostOrderEnumerator:IEnumerator { /* ...latosa implementacin de los mtodos MoveNext y Current */ } }

Note el foreach (object x in t) yield return x ; anidado dentro del foreach ms externo, aqu estamos usando recursivamente el propio concepto de iterador ahora aplicado a cada uno de los hijos del rbol original.

Ms de un iterador para una misma clase


Se podr usar como iterador todo mtodo que devuelva un IEnumerator o un IEnumerable y que incluya un yield. Con esto se supera una limitacin anterior en C# que forzaba a estar definiendo clases IEnumerable slo con la intencin de devolver un IEnumerator a travs del mtodo GetEnumerator. Suponga, para un ejemplo como el de la clase rbol, que se quieren tener dos formas de iteracin: una preorden y otra en postorden. La solucin en C# 2.0 es tan simple como:
class Tree { object nodeValue; public ArrayList Nodes { get{} } public IEnumerable PreOrder { get { yield return nodeValue; foreach (Tree t in Nodes) foreach (object x in t) yield return x; } } public IEnumerable PostOrder { get { foreach (Tree t in Nodes) foreach (object x in t) yield x; yield nodeValue; } } }

Si queremos que se pueda hacer un recorrido foreach (object x in t) directamente sobre la propia variable rbol, supongamos se asume en este caso el recorrido en preorden como recorrido predeterminado (by default), se puede definir la clase Tree del modo siguiente (note que incluso mantenemos el recorrido con nombre a travs de la propiedad PreOrder)
class Tree: IEnumerable { object nodeValue; public ArrayList Nodes { get{} } public IEnumerator GetEnumerator() { yield return nodeValue; foreach (Tree t in Nodes) foreach (object x in t) yield return x; } public IEnumerable PreOrder { get { return this; } } public IEnumerable PostOrder { get { foreach (Tree t in Nodes) foreach (object x in t) yield x; yield nodeValue; } } }

Una implementacin de iteradores usando hebras


Veremos en esta seccin como podemos implementar este concepto de iterador utilizando hebras. La solucin se basa en utilizar un tipo especial Iterator que implementa a IEnumerable. Para crear un objeto de tipo Iterator hay que ofrecer un objeto delegate del tipo:
public delegate void IteratorMethod(IYield yieldObject);

class Tree: IEnumerable { ...

29

<<dotNetMana

Note la implementacin de la propiedad PostOrder en el ejemplo anterior de Tree, en el get hemos incluido directamente el cdigo del iterador. Con esto nos evitamos tener que escribir el par de clases internas PostOrderEnumerable y PostOrderEnumerator como se muestra en el extracto de cdigo a continuacin:

El mtodo que se asocie a este objeto delegate ser el que encierre el verdadero proceso de iteracin (que puede incluir la complejidad de una recursin). Cuando producto de aplicar el patrn que se muestra en la Tabla 1, se hace el primer MoveNext, ste echar a andar una hebra asociada al delegate anterior. Esta hebra sincronizar con la hebra que la cre (aquella del cdigo cliente que ha desencadenado el ciclo foreach) mediante un objeto especial de tipo IYield que se usar dentro del cuerpo del mtodo del delegate.

<< dnm.plataforma
public interface IYield { void Yield(object result); } Hacer y.Yield(x) significa poner a x como valor del Current del enumera-

dor y detener la hebra en ese punto hasta que por demanda del cdigo cliente a travs del foreach se vuelva a invocar a un prximo MoveNext. El cdigo fuente 1 ilustra cmo incluir en una clase Tree un iterador en preorden. La instruccin en la lnea 12

de la hebra hasta que se vuelva a invocar a un prximo MoveNext (ver ms adelante el cdigo fuente 2 con la implementacin de la clase Iterator) producto de una nueva iteracin del cdigo cliente (instruccin lnea 30). En el cdigo fuente 2 se muestra la implementacin de la clase Iterator, note que el mtodo MoveNext (lnea 34) es quien desencadena la hebra cuando es llamado por primera vez al aplicar el cdigo cliente el patrn de la tabla 2.

1. class Tree 2. { 3. object nodeValue; 4. ... 5. public ArrayList Nodes 6. { 7. get{...} 8. } 9. public IEnumerable PreOrder 10. { 11. get 12. {return new Iterator(new IteratorMethod(PreOrderMethod)); 13. } 14. } 15. void PreOrderMethod(IYield y) 16. { 17. PreOrderMethod(y, this); 18. } 19. void PreOrderMethod(IYield y, Tree t) 20. { 21. y.Yield(t.nodeValue); 22. foreach (Tree t1 in t.Nodes) PreOrderMethod(y, t1); 23. } 24. } 25. class TreeTest 26. { 27. public static void Main() 28. { 29. Tree t = ...; 30. foreach (object x in t.PreOrder) 31. Console.WriteLine(x); 32. } 33. }

El mtodo runMethod de la hebra es quien llama al delegate con la instruccin it(this) (lnea 30) que es quien realmente hace la iteracin y usa al propio objeto this (que es de tipo IYield ) para ejecutar las acciones Yield. El mtodo MoveNext queda en espera de la seal calculatedValue (lnea 47) que es enviada por el mtodo Yield cuando se ha calculado un nuevo valor (lnea 67) o por el propio mtodo runMethod cuando se ha terminado la iteracin (lnea 32) y no hay ms objetos que calcular para la iteracin. El mtodo Reset (lnea 72) manda a abortar la hebra. Esto ocurrira en el caso en que el cdigo cliente haga un Reset an cuando no se haya llegado al final de la iteracin. Las hebras son recursos limitados de modo que hay que garantizar que si el cdigo cliente aborta un ciclo foreach (por ejemplo con una instruccin break o return) la hebra de la iteracin no quede viva innecesariamente, por esta razn la clase CoroutineEnumerator se ha definido como IDisposable . Note que en la definicin de Dispose tambin se manda a abortar la hebra (lnea 77).

Cdigo fuente 1. Iterador PreOrder dentro de un rbol

<<dotNetMana

asocia al iterador el delegate formado por el mtodo de la lnea 15 (que a su vez llama al mtodo de la lnea 19). Note la instruccin y.Yield(t.nodeValue); de la lnea 21, el lector debe imaginar como si aqu se detuviera la ejecucin

IEnumerator e = list.GetEnumerator(); while(e.MoveNext()) { object x = e.Current; ... Process x; }

Figura 1. Movimientos en las Torres

Hanoi para 3 discos

30

<< dnm.plataforma
1.public class Iterator: IEnumerable 2.{ 3. IteratorMethod it; 4. public Iterator(IteratorMethod it) 5. { 6. if (it == null) 7. throw new ArgumentNullException(); 8. this.it = it; 9. } 10. public IEnumerator GetEnumerator() 11. { 12. return new CoroutineEnumerator(it); 13. } 14. //Inner class 15. class CoroutineEnumerator:IEnumerator, IDisposable,IYield 16. { 17. IteratorMethod it; 18. Thread itThread; 19. object current; 20. bool finish; 21. object proceedIteration = new object(); 22. object calculatedValue = new object(); 23. public CoroutineEnumerator(IteratorMethod iterator) 24. { 25. this.iterator = iterator; 26. } 27. void runMethod() { 28. finish = false; 29. //Initialize a thread with the handler 30. it(this); 31. finish = true; 32. lock(calculatedValue) {Monitor.Pulse(calculatedValue);} 33. } 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. } public object Current { get { if (finish) throw new InvalidOperationException( "Invalid Current. Out of the collection"); else return current; } }

60. void IYield.Yield(object result) 61. { 62. lock (proceedIteration) 63. { 64. lock (calculatedValue) 65. { 66. current = result; 67. Monitor.Pulse(calculatedValue); 68. } 69. Monitor.Wait(proceedIteration); 70. } 71. } 72. public void Reset() 73. { 74. try 75. { 76. if (itThread.IsAlive) 77. itThread.Abort(); 78. } 79. catch(ThreadAbortException){}; 80. itThread = null; 81. finish = true; 82. } 83. ~CoroutineEnumerator() 84. { 85. Dispose(); 86. }

Cdigo fuente 2. Implementacin de Iterator

31

<<dotNetMana

34. public bool MoveNext() 87. public void Dispose() 35. { 88. { 36. lock(calculatedValue) 89. if (itThread != null) 37. { 90. { 38. if (itThread == null) 91. try 39. { { 40. itThread = new Thread(new ThreadStart(runMethod )); 92. 93. itThread.Abort(); 41. itThread.Start(); 94. } 42. } 95. catch(ThreadAbortException){}; 43. lock (proceedIteration) 96. itThread = null; 44. { 97. } 45. Monitor.Pulse(proceedIteration); 98. } 46. } 99. } 47. Monitor.Wait(calculatedValue); 100. } 48. } 101.} 49. return !finish;

<< dnm.plataforma
Un iterador para los movimientos de las Torres de Hanoi
El juego de Las Torres de Hanoi consiste en disponer de tres torres (como se ilustra en la Figura 1). En una de las torres hay un conjunto de discos de mayor a menor. Se quieren pasar todos los discos desde una torre origen hacia una torre destino, pudiendo usarse la tercera torre como auxiliar, pero con la restriccin de que slo puede moverse un disco por vez y que nunca se puede poner un disco mayor sobre uno menor. Como se muestra a continuacin un mtodo para listar todos los movimientos es muy simple usando recursin
void Hanoi(int disks, string source, string target, string aux) { if (disks == 1) Console.WriteLine( Move from + source + to + target); else { Hanoi(disks-1,source, aux, target); Console.WriteLine(Move from + source + a + target); Hanoi(disks-1,aux, target, source); } } new IteratorMethod(HanoiMethod));} } void HanoiMethod(IYield y) { HanoiMethod(y, disks, source, target, aux); } void HanoiMethod(IYield y, int disks, string source, string target, string aux) { if (disks==1) y.Yield(Move from + source + to + target); else { HanoiMethod(y, disks-1,source, aux, target); y.Yield(Move from + source + to + target); HanoiMethod(y, disks-1,aux, target, source); } } }

Pruebe sin embargo el lector a implementar un


IEnumerable que devuelva las cadenas de cada uno de

los movimientos. Note que tendra prcticamente que programar toda la maquinaria que el proceso recursivo anterior esconde. La solucin utilizando el tipo Iterator es muy simple:
class Hanoi { int disks; string target, source, aux; public Hanoi(int disks, string source, string target, string aux) { this.disks=disks; this.source=source; this.target=target; this.aux=aux; }

Figura 2. Movimientos de 3 discos en las Torres Hanoi.

La ejecucin del siguiente cdigo listara lo que se muestra en la figura 2.


HanoiIterator hanoi = new HanoiIterator(3, A, B, C); foreach (string s in hanoi) Console.WriteLine(s);

<<dotNetMana

public IEnumerable Movements { get { return new Iterator(

No hay ningn problema en anidar el uso de un iterador dentro de otro, el siguiente cdigo listara lo que se muestra en la figura 3.

32

<< dnm.plataforma
llado en este trabajo, deba ser la solucin general de implementacin para tener iteradores ya que las hebras son un recurso caro y limitado. Las descripciones sobre cmo ser implementado este recurso de iteradores por el compilador de C# 2.0 de VS C# 2005 (ver [1] y [4]) indican que el nuevo compilador de Microsoft para C# 2.0 generar clases anidadas que encapsularn la mquina de estado de la iteracin, lo cual es realmente la solucin adecuada pero que slo puede hacerse sobre la base de desarrollar un nuevo compilador. Sin embargo, la implementacin mediante hebras que hemos mostrado en este artculo, adems de ilustrar la utilizacin de las hebras, permite que los programadores que no dispongan an de C# 2.0 puedan mientras tanto irse habituando al til nivel de expresividad que los iteradores proporcionan, evitando el trabajo y los errores que la complejidad de la programacin manual de la maquinaria recursiva de una iteracin puede ocasionar. Esta implementacin con hebras trabaja de modo sncrono pero pudiera desarrollarse una solucin asncrona. Es decir que, si el cdigo cliente lo desea, entonces el iterador pueda ir calculando asncronamente el prximo elemento mientras el cliente procesa el anterior lo cual puede ser una alternativa interesante para aplicaciones distribuidas.

Figura 3. Iteradores anidados.

HanoiIterator hanoi1 = new HanoiIterator(2, A, B,C); HanoiIterator hanoi2 = new HanoiIterator(2, Left, Rigth, Center); foreach (string s1 in hanoi1) { Console.WriteLine(s1); foreach (string s2 in hanoi2) Console.WriteLine(- + s2); }

significa que el compilador estticamente garantizar que el objeto que devuelva un yield return tenga que ser de tipo T y que los elementos sobre los que se itere en el foreach sean de tipo T. Lo cual redunda en mayor legibilidad, ms robustez y ms eficiencia al disminuir la necesidad de operaciones

Conclusiones
La uniformidad que propone .NET en el uso de enumeradores es importante para el tratamiento de colecciones y es usado ampliamente en sus propias bibliotecas. El aporte del ciclo foreach es una comodidad sintctica considerable y menos propensa a errores. La anunciada inclusin de iteradores para C#2.0 ser muy bienvenida porque aumentar la expresividad y elegancia del cdigo. Sera deseable que se considerase la inclusin de operadores lgicos forall y exists asociados a este concepto de iteradores ya que esto redundara en beneficio de las capacidades de abstraccin y diseo utilizando C#. En C# 2.0 esta capacidad de iteradores se potencia al mximo cuando sea utilizada en combinacin con la genericidad, nuevo esperado recurso que tambin est incluido en C# 2.0. Con genericidad un iterador podr devolver un objeto de tipo IEnumerator<T> lo que

La anunciada inclusin de iteradores para C#2.0 ser muy bienvenida porque aumentar la expresividad y elegancia del cdigo. Sera deseable que se considerase la inclusin de operadores lgicos forall y exists asociados a este concepto de iteradores...
de casting en tiempo de ejecucin. La genericidad es tambin un tema muy importante a tratar por futuros artculos de dotNetMana pero que por razones de espacio no ha sido abordado ahora aqu. No creemos que una solucin usando hebras, como la que hemos desarro-

Referencias
[1] The C# 2.0 Specification , http://download.microsoft.com/download/8/1/6/81682478-4018-48fe-9e5ef87a44af3db9/SpecificationVer2.doc [2] Katrib M, Martnez I, Collections and Iterators in Eiffel, Journal of Object Oriented Programming, Vol 6, No 7, Nov/Dec 1993. [3] Coira J, Katrib M, Improving Eiffel assertions using quantified iterators, Journal of Object Oriented Programming, Vol 10, No 7, Nov/Dec 1997. [4] Lowy Juval, Create Elegant Code with Anonymous Methods, Iterators, and Partial Classes, MSDN Magazine, May 2004.

33

<<dotNetMana

You might also like